2.09. Основы интеграционного взаимодействия
Интеграция
Современные программные системы, даже самые автономные на первый взгляд, крайне редко существуют в полной изоляции. Даже локальное приложение, не подключённое к интернету, может взаимодействовать с операционной системой, использовать системные библиотеки или сохранять данные в файловую систему — всё это формы интеграции. Однако в промышленной, корпоративной и веб-разработке интеграция приобретает особую значимость, поскольку бизнес-процессы, пользовательские сценарии и технические архитектуры требуют координации множества независимых компонентов.
Интеграционное взаимодействие — это совокупность механизмов, протоколов, принципов и практик, посредством которых программные системы обмениваются данными, координируют поведение и совместно реализуют сложные функциональные требования. Без таких механизмов невозможно построить распределённую, масштабируемую и гибкую архитектуру.
Что такое интеграция? Как она соотносится с коммуникацией и взаимодействием?
Термины интеграция, коммуникация и взаимодействие часто используются как синонимы, но в техническом контексте они описывают разные уровни и аспекты одного и того же явления.
Интеграция — это процесс и результат объединения двух или более автономных систем с целью достижения функциональной целостности. Интеграция предполагает не только обмен данными, но и согласование семантики, форматов, протоколов, политик безопасности и жизненных циклов. Например, интеграция CRM-системы с платёжным шлюзом включает не только передачу суммы и идентификатора заказа, но и согласование статусов транзакций, обработку ошибок и восстановление после сбоев.
Коммуникация — это технический акт передачи информации от одного участника к другому. Это уровень сигнала: байты передаются по каналу связи, с использованием того или иного транспортного протокола (TCP, HTTP, AMQP и т.д.). Коммуникация может быть успешной с технической точки зрения, даже если смысл сообщения не понят получателю.
Взаимодействие — это семантический и функциональный уровень общения систем. Оно включает не только передачу данных, но и ожидание определённого поведения в ответ. Например, отправка запроса на авторизацию подразумевает не просто доставку токена, но и проверку его валидности, выдачу прав доступа и потенциальную генерацию сессии. Взаимодействие предполагает наличие контракта — явного или неявного — между сторонами.
Таким образом, интеграция охватывает взаимодействие, которое, в свою очередь, использует коммуникацию как транспортный механизм.
Почему программы не работают сами по себе?
На первый взгляд, автономное программное обеспечение — например, редактор текста или игра — может функционировать полностью независимо. Однако даже в таких случаях присутствуют формы взаимодействия:
- с операционной системой (через системные вызовы, файловую систему, устройства ввода-вывода);
- с пользователем (через интерфейс, который сам по себе является формой диалога);
- с внешними библиотеками или службами (например, проверка обновлений, синхронизация настроек в облако).
В корпоративной среде изоляция практически невозможна. Бизнес-процессы часто распределены между различными доменами: продажи, финансы, логистика, поддержка. Каждый из них обслуживается отдельной системой: ERP, CRM, WMS, биллинг, аналитика. Для выполнения даже простой операции — например, оформления заказа — требуется координация множества систем. Ни одна из них не обладает полной информацией о контексте; только совместная работа позволяет принять корректное решение.
Более того, современные архитектурные стили — микросервисы, event-driven architecture, serverless — основаны на декомпозиции функционала на независимые компоненты, которые обязаны взаимодействовать. Изоляция здесь — не недостаток, а достоинство: она повышает устойчивость, упрощает развертывание и позволяет масштабировать отдельные части независимо. Однако эта изоляция делает интеграцию не просто желательной, а необходимой.
Как общаются системы?
Общение систем строится на нескольких фундаментальных принципах:
-
Наличие общего протокола — системы должны использовать один и тот же транспортный и прикладной протокол (например, HTTP/1.1, gRPC, MQTT). Протокол определяет синтаксис сообщений, порядок обмена, правила ошибок.
-
Согласование формата данных — даже при использовании одного протокола данные могут передаваться в разных форматах: JSON, XML, Protocol Buffers, Avro. Формат должен быть согласован заранее или определён динамически (например, через MIME-типы в HTTP).
-
Семантический контракт — стороны должны понимать не только структуру данных, но и их смысл. Например, поле
amountможет быть в центах или в рублях; значениеstatus: "confirmed"может означать разное в разных системах. Контракт часто формулируется в виде OpenAPI, AsyncAPI, GraphQL-схемы или просто в технической документации. -
Политики взаимодействия — это правила, определяющие, когда, как часто и при каких условиях допустимо взаимодействие. Сюда относятся ограничения по скорости (rate limiting), требования к надёжности (retry policy), временные окна доступности (SLA), а также правила обработки ошибок.
-
Контекст безопасности — почти любое взаимодействие осуществляется в рамках доверенной среды. Это требует аутентификации, авторизации, шифрования и аудита.
Без соблюдения хотя бы одного из этих принципов общение либо невозможно, либо приводит к ошибкам, несогласованности данных или уязвимостям.
Виды взаимодействия: синхронное, асинхронное, реактивное
Выбор модели взаимодействия определяет архитектурные свойства системы: отзывчивость, устойчивость к сбоям, сложность отладки и масштабируемость.
Синхронное взаимодействие предполагает, что инициатор запроса ждёт ответа до продолжения своей работы. Классический пример — HTTP-запрос к REST API. Пока ответ не получен, вызывающая система блокирована (или работает в режиме ожидания). Преимущества: простота логики, предсказуемость последовательности операций. Недостатки: блокировка ресурсов, зависимость от времени отклика удалённой системы, низкая устойчивость к сбоям.
Асинхронное взаимодействие разрывает прямую связь во времени между отправкой сообщения и его обработкой. Инициатор не ждёт ответа и продолжает работу. Сообщение помещается в промежуточную очередь (например, RabbitMQ, Kafka, AWS SQS), из которой его забирает получатель, когда будет готов. Преимущества: декуплинг компонентов, устойчивость к кратковременным сбоям, масштабируемость. Недостатки: усложнение логики обработки ошибок, необходимость отслеживания состояния, потенциальная несогласованность данных.
Реактивное взаимодействие — это эволюция асинхронной модели, основанная на принципах реактивного программирования (Reactive Manifesto). Здесь системы не просто посылают сообщения, а обмениваются потоками событий, реагируют на изменения состояния, применяют backpressure для управления нагрузкой. Примеры: WebSocket-каналы, стриминг через gRPC, реактивные фреймворки (Project Reactor, RxJava). Реактивность позволяет строить высоконагруженные, отзывчивые системы, но требует переосмысления традиционных подходов к обработке данных и ошибок.
Эти модели не являются взаимоисключающими. В одной системе могут сосуществовать синхронные вызовы для пользовательского интерфейса, асинхронные события для внутренней обработки и реактивные потоки для аналитики.
Концепция автономности систем и трансформация данных
Фундаментальный принцип распределённых систем заключается в том, что каждая из них существует и функционирует автономно. Это означает, что:
- система обладает собственной логикой обработки данных;
- управляет собственным состоянием (часто — через локальную или выделенную базу данных);
- имеет независимый жизненный цикл разработки, развертывания и масштабирования;
- не зависит от внутреннего устройства других систем.
Автономность — условие устойчивости и гибкости архитектуры. Однако она порождает новую проблему: данные, необходимые для выполнения сквозного бизнес-процесса, физически и логически распределены. Чтобы координировать действия, системы должны обмениваться информацией, но эта информация редко бывает совместимой «из коробки».
Здесь возникает необходимость трансформации данных — преобразования структуры, семантики и формата информации из представления, понятного отправителю, в представление, пригодное для получателя.
Трансформация может происходить на нескольких уровнях:
-
Синтаксическая трансформация: изменение формата данных без изменения смысла. Например, преобразование XML в JSON, или сериализация объекта в Protocol Buffers. Такие преобразования часто выполняются шлюзами (API Gateway), адаптерами (в паттерне Enterprise Integration Patterns) или ETL-процессами.
-
Семантическая трансформация: приведение значений к общему смысловому контексту. Пример: система А передаёт статус заказа как
“shipped”, а система Б понимает только“dispatched”. Здесь требуется маппинг значений, возможно — с использованием справочников или онтологий. -
Агрегационная трансформация: сборка данных из нескольких источников в единое сообщение. Например, для формирования единого карточки клиента может потребоваться информация из CRM, биллинг-системы и службы поддержки. Такая трансформация часто реализуется в оркестраторах (BPM-движки, Saga-оркестрация) или через композитные API.
-
Проекционная трансформация: отбор только тех полей или сущностей, которые необходимы получателю. Это снижает объём передаваемых данных и повышает безопасность (принцип минимальных привилегий).
Трансформация — неотъемлемая часть интеграционного слоя. Она может быть реализована программно (в коде микросервиса), декларативно (через правила в интеграционной платформе, например, ELMA365 или Apache Camel), или с помощью специализированных сервисов (Data Transformation Service в облаке).
Что такое интеграционные потоки?
Интеграционный поток — это последовательность шагов, через которые проходят данные при перемещении между системами. Поток отражает логику обработки: от приёма сообщения до его доставки, включая возможные трансформации, проверки, маршрутизацию и реакцию на ошибки.
Ключевые характеристики интеграционного потока:
- Направленность: поток может быть однонаправленным (отправка уведомления), двунаправленным (запрос-ответ) или многоточечным (публикация в шину событий с несколькими подписчиками).
- Оркестрация vs хореография: в оркестрованном потоке существует центральный координатор, управляющий последовательностью вызовов (например, BPM-движок). В хореографии каждая система реагирует на события независимо, без централизованного контроля.
- Идемпотентность и атомарность: качественно спроектированный поток должен учитывать возможность повторной отправки сообщений (идемпотентность) и обеспечивать согласованность данных при частичных сбоях (через Saga-паттерн или компенсирующие транзакции).
- Наблюдаемость: поток должен быть инструментирован — логирование, трассировка (distributed tracing), метрики — для диагностики и аудита.
Интеграционные потоки часто визуализируются в виде диаграмм последовательностей (sequence diagrams) или BPMN-схем. В промышленных платформах (например, BPMSoft, ELMA365, Apache NiFi) такие потоки могут конфигурироваться декларативно, без написания кода, что упрощает сопровождение и версионирование.
Что такое интеграционная авторизация?
Интеграционная авторизация — это механизм, посредством которого одна система получает право выполнять определённые действия в другой системе в рамках интеграционного взаимодействия.
В отличие от пользовательской авторизации, где субъект — человек с ролью или правами, в интеграционном контексте субъектом выступает система (или её компонент: микросервис, функция, шлюз). Поэтому применяются специфические модели доверия.
Наиболее распространённые подходы:
-
API-ключи — простой, но ограниченный метод. Ключ передаётся в заголовке запроса и идентифицирует вызывающую систему. Однако ключ не обеспечивает аутентификацию личности (только идентификацию источника) и уязвим при утечке.
-
OAuth 2.0 Client Credentials Flow — стандартный способ авторизации машина-машина (M2M). Система (клиент) аутентифицируется в авторизационном сервере с помощью
client_idиclient_secret, получает JWT-токен и использует его для доступа к API. Токен может содержать права (scopes), ограничивающие доступ. -
mTLS (mutual TLS) — двусторонняя аутентификация на уровне транспорта. Каждая сторона предоставляет сертификат, подтверждающий её подлинность. Применяется в высокозащищённых средах (финансы, государственные системы).
-
Service Accounts — в облачных платформах (Google Cloud, AWS IAM Roles) компоненты могут получать временные учётные данные с точно определёнными привилегиями. Это соответствует принципу наименьших привилегий и автоматическому ротированию ключей.
Интеграционная авторизация должна быть строго привязана к контексту: какая система, зачем, какие действия, на какие ресурсы. Отсутствие такой привязки приводит к избыточным правам и росту поверхности атаки.
Как открываются и закрываются сессии в интеграционном контексте?
В классическом веб-приложении сессия — это временный контекст, связанный с пользователем, сохраняющий состояние между запросами (например, через cookie). В интеграционном взаимодействии понятие сессии применяется иначе.
Сессия в интеграции — это логический контекст, объединяющий несколько связанных операций между системами. Она может быть явной или неявной.
-
Явная сессия: некоторые протоколы (например, SOAP с WS-Security, или FTP) требуют явного установления сессии: вызов метода
openSession(), получение идентификатора сессии, передача его в последующих запросах, завершение черезcloseSession(). Такой подход характерен для stateful-сервисов. -
Неявная сессия: в REST и других stateless-архитектурах сессия не хранится на сервере. Вместо этого каждый запрос должен быть самодостаточным и содержать все необходимые данные (включая токен авторизации). Логическая сессия может существовать только на стороне клиента или в промежуточной системе (например, API Gateway агрегирует несколько вызовов в один пользовательский сценарий).
Закрытие сессии — это не только освобождение ресурсов, но и завершение контекста доверия. В случае компрометации токена или ключа сессия должна быть немедленно инвалидирована (например, через механизм отзыва токенов в OAuth 2.0 — Token Revocation).
Важно понимать, что в большинстве современных интеграций stateless-подход предпочтителен, так как он упрощает масштабирование и повышает отказоустойчивость. Однако в сложных транзакционных сценариях (например, передача большого файла частями или многозадачная обработка) может потребоваться управляемый сессионный контекст.
История интеграций
Историю интеграций можно условно разделить на несколько эпох, каждая из которых характеризуется доминирующей архитектурной моделью, типичными технологиями и фундаментальными ограничениями.
Эпоха монолитов и файловых интерфейсов (1960–1980-е)
На ранних этапах развития вычислительной техники программное обеспечение было тесно связано с аппаратной платформой. Операционные системы отсутствовали или были примитивными, а программы зачастую писались на ассемблере под конкретную машину. В таких условиях «интеграция» сводилась к передаче данных через файлы.
Типичный сценарий: одна программа записывала выходные данные в файл определённого формата на магнитную ленту или диск; другая программа считывала этот файл и интерпретировала его содержимое. Согласование формата происходило на уровне соглашений между разработчиками или через стандартизированные структуры (например, COBOL copybooks).
Преимущества такого подхода — простота и полная изоляция процессов. Недостатки — высокая задержка (batch processing), отсутствие обратной связи, сложность отладки при несовпадении форматов и полная зависимость от внешнего расписания (job scheduler).
Несмотря на архаичность, файловый обмен не исчез: он сохранился в ETL-процессах, банковских выгрузках и legacy-системах, где транзакционная целостность важнее оперативности.
Эпоха корпоративных клиент-серверных систем и RPC (1980–1990-е)
С распространением локальных сетей и развитием операционных систем (UNIX, Windows NT) возникла возможность прямого вызова процедур на удалённых машинах. Это привело к появлению удалённых вызовов процедур (Remote Procedure Call, RPC).
RPC маскировал сетевое взаимодействие под локальный вызов функции. Разработчик писал код так, будто вызывает обыкновенную подпрограмму, а middleware (например, ONC RPC, DCE/RPC) отвечал за сериализацию аргументов, передачу по сети и десериализацию результата.
В корпоративной среде RPC лег в основу таких технологий, как:
- CORBA (Common Object Request Broker Architecture) — платформенно-независимый стандарт от OMG;
- DCOM (Distributed Component Object Model) — Microsoft-решение для распределённых COM-объектов;
- RMI (Remote Method Invocation) — механизм для Java-приложений.
Эти системы вводили понятие объектной интеграции: компоненты взаимодействовали не через данные, а через поведение. Однако они страдали от жёсткой связанности (tight coupling): изменение интерфейса на стороне сервера немедленно нарушало совместимость клиента. Кроме того, большинство решений были закрытыми, несовместимыми между собой и плохо масштабировались за пределы локальной сети.
Эпоха веб-сервисов и SOA (2000–2010-е)
Появление интернета и стандарта HTTP как универсального транспорта создало предпосылки для нового подхода: интеграция через документы, а не через вызовы. Это стало основой Service-Oriented Architecture (SOA).
Ключевые технологии эпохи:
- XML — универсальный язык структурированных данных;
- SOAP (Simple Object Access Protocol) — протокол обмена сообщениями на основе XML;
- WSDL (Web Services Description Language) — описание интерфейса сервиса;
- UDDI (Universal Description, Discovery, and Integration) — каталог сервисов (в итоге не прижился);
- ESB (Enterprise Service Bus) — централизованная шина интеграции, обеспечивающая маршрутизацию, трансформацию, мониторинг.
SOA декларировала принципы: повторное использование, слабая связанность, стандартизация контрактов. Однако на практике многие реализации SOA превращались в монолитные, тяжеловесные архитектуры с централизованным контролем (через ESB), где любое изменение требовало координации множества команд.
Несмотря на критику, SOA заложила важнейшие идеи:
- явное описание контрактов;
- отделение интерфейса от реализации;
- интеграция как первоклассная задача архитектуры.
Эпоха REST, микросервисов и событийной архитектуры (2010–2020-е)
Реакцией на тяжеловесность SOAP и централизованной SOA стало движение REST (Representational State Transfer), основанное на принципах HTTP и ресурсно-ориентированного взаимодействия. REST предложил:
- использование стандартных HTTP-методов (GET, POST, PUT, DELETE);
- stateless-подход;
- передачу данных в лёгких форматах (JSON, позже — Protocol Buffers);
- декларативное описание API через OpenAPI/Swagger.
Одновременно с этим развитие DevOps, контейнеризации (Docker) и оркестрации (Kubernetes) позволило массово внедрять микросервисную архитектуру, в которой интеграция стала не исключением, а нормой.
Важнейшим сдвигом стало признание асинхронности как основы масштабируемости. Вместо синхронных вызовов всё чаще использовались события (events): система публиковала факт изменения состояния, а другие системы реагировали на него по своему усмотрению. Это привело к распространению:
- брокеров сообщений (RabbitMQ, Apache Kafka, Amazon SNS/SQS);
- event-driven architecture (EDA);
- паттернов вроде Saga для управления распределёнными транзакциями.
Интеграция перестала быть задачей централизованного middleware и стала распределённой ответственностью команд. Возникли новые вызовы: управление версиями API, согласованность данных в отсутствие глобальных транзакций, наблюдаемость сквозных потоков.
Современная эпоха: API-экономика, serverless и унифицированные интеграционные платформы (2020-е и далее)
Сегодня интеграция вышла за пределы внутренней инфраструктуры организаций. API стали продуктом: компании монетизируют доступ к своим данным и функциям через публичные API (Stripe, Twilio, Google Maps). Это породило понятие API-экономики.
Параллельно развиваются:
- Serverless-интеграции: функции как интеграционные точки (AWS Lambda, Azure Functions), запускаемые по событию;
- Low-code/no-code интеграционные платформы: Zapier, Make (Integromat), ELMA365, BPMSoft — позволяют конфигурировать потоки без написания кода;
- Unified API и iPaaS (Integration Platform as a Service): инструменты, унифицирующие доступ к множеству SaaS-систем через единый интерфейс;
- GraphQL и gRPC: альтернативы REST для сложных запросов и высокопроизводительных сценариев.
Особое внимание уделяется безопасности (Zero Trust, mTLS, OAuth 2.0), наблюдаемости (OpenTelemetry) и управлению жизненным циклом API (API governance).
Веб-сервисы
Происхождение термина «сервис» и его семантическая нагрузка в контексте распределённых систем
Термин «сервис» (от лат. servitium — служба, подчинение) исторически обозначает действие, совершаемое одним субъектом в интересах другого. В контексте вычислительных систем понятие «сервис» унаследовало эту семантику: это программная функциональность, предоставляемая одной программной сущностью (провайдером) по запросу другой (клиента) с соблюдением заранее определённого контракта. Слово «сервер», в свою очередь, происходит от французского servir — «служить», и этимологически укрепляет связь между понятиями «служить» и «предоставлять». В архитектуре распределённых систем сервер — это не просто аппаратная или программная единица, а именно субъект, оказывающий услугу другим участникам взаимодействия.
Таким образом, «веб-сервис» — это не просто программа, доступная через сеть, а строго определённая программная возможность, экспонированная через веб-интерфейс и используемая в парадигме «запрос–ответ» или «публикация–подписка», при этом соблюдается принцип чёткого разграничения ответственности: клиент формулирует потребность, сервис реализует логику её удовлетворения. Важно подчеркнуть: веб-сервис не требует от клиента знания внутреннего устройства реализации — достаточно понимания контракта, который определяет входные и выходные данные, допустимые состояния и возможные ошибки. Это принцип инкапсуляции, перенесённый из объектно-ориентированного программирования в область сетевых взаимодействий.
Определение веб-сервиса как архитектурного паттерна
Веб-сервис — это программный компонент, реализующий конкретную бизнес-функцию или техническую операцию, доступный через стандартные веб-протоколы, прежде всего HTTP/HTTPS, и предоставляющий взаимодействие посредством машиночитаемых сообщений. Такое определение подчеркивает три ключевых аспекта:
- Функциональная обособленность: веб-сервис реализует одну или несколько связанных операций, составляющих логически завершённую задачу — например, проверку баланса счёта, конвертацию валюты, идентификацию пользователя.
- Стандартизация транспорта: веб-сервис использует открытые, широко распространённые сетевые протоколы, в первую очередь HTTP(S), что обеспечивает совместимость с любыми платформами и языками программирования, способными выполнять HTTP-запросы.
- Машиночитаемость контракта: взаимодействие между клиентом и веб-сервисом строится не на человеческом интерфейсе (вроде HTML-страницы), а на форматированных данных — XML, JSON или специализированных бинарных форматах, что позволяет автоматизировать вызовы и обработку результатов.
Это отличает веб-сервисы от традиционных веб-сайтов, ориентированных на визуальное представление информации человеку. Веб-сервисы предназначены для программного потребления — они являются «кирпичами», из которых строятся распределённые приложения, составные системы и сложные цифровые экосистемы.
Следует также проводить чёткое разграничение между веб-сервисом как концепцией и веб-API как её реализацией. Любой веб-API — это интерфейс к веб-сервису, но не всякий веб-API подразумевает соблюдение всех формальных признаков веб-сервиса (например, машинно-интерпретируемый контракт в виде WSDL или OpenAPI). В то же время в инженерной практике оба термина часто используются как синонимы, хотя концептуально веб-сервис шире.
Историческое развитие парадигмы веб-сервисов
Идея программного взаимодействия через сеть существовала задолго до появления World Wide Web. Удалённые вызовы процедур (RPC), CORBA, DCOM — всё это были попытки стандартизировать межпроцессное взаимодействие в распределённых системах. Однако эти решения страдали от привязки к платформам, сложности настройки и отсутствия универсального транспорта. Появление HTTP как простого, статус-ориентированного протокола с широкой поддержкой на всех уровнях сетевого стека (от браузеров до файрволов) создало предпосылки для нового подхода.
Первые спецификации веб-сервисов (SOAP, WSDL, UDDI), появившиеся в конце 1990-х — начале 2000-х годов, стремились к максимальной формализации: машинно-интерпретируемый контракт, строгая типизация данных, встроенная поддержка безопасности и транзакций. Однако сложность и избыточность SOAP-стека привели к появлению альтернативного подхода — REST (Representational State Transfer), предложенного Ройем Филдингом в 2000 году как архитектурный стиль, а не протокол. REST-подход опирался на естественные свойства HTTP (методы, коды состояний, заголовки) и стал доминирующим в эпоху мобильных приложений и облачных сервисов.
Таким образом, эволюция веб-сервисов — это путь от жёстко формализованных, самодокументируемых, но громоздких систем к лёгким, гибким и ориентированным на разработчика API, основанным на простых текстовых форматах и принципах REST.
Классификация веб-сервисов
Веб-сервисы можно классифицировать по нескольким критериям. Наиболее значимыми являются:
По архитектурному стилю
-
SOAP-ориентированные веб-сервисы
Основаны на протоколе SOAP (Simple Object Access Protocol) — XML-базированном протоколе обмена сообщениями. Характеризуются:- Использованием WSDL (Web Services Description Language) для описания интерфейса;
- Поддержкой WS-* стандартов (WS-Security, WS-ReliableMessaging, WS-Transaction и др.);
- Строгой типизацией и схемами XSD;
- Поддержкой асинхронных вызовов и сообщений с гарантированной доставкой;
- Высокой степенью формальности и самодокументируемости.
Такие сервисы часто применяются в корпоративных системах, финансовых институтах, государственных структурах, где важны детерминированность, безопасность и соответствие регуляторным требованиям.
-
RESTful-сервисы
Следуют архитектурному стилю REST и используют HTTP как платформу. Характеризуются:- Идентификацией ресурсов через URI;
- Использованием стандартных HTTP-методов (GET, POST, PUT, DELETE и др.);
- Отсутствием состояния на стороне сервера (statelessness);
- Представлением ресурсов в форматах JSON, XML или других (чаще всего JSON);
- Гипермедиа как движущей силой состояния (HATEOAS), хотя на практике этот принцип часто опускается.
RESTful-сервисы доминируют в современной веб- и мобильной разработке благодаря простоте, масштабируемости и удобству для разработчиков.
-
GraphQL-сервисы
Являются относительно новым подходом, предложенным Facebook в 2015 году. В отличие от REST, где клиент запрашивает фиксированные ресурсы по заданным эндпоинтам, GraphQL предоставляет единую точку входа, через которую клиент описывает структуру желаемых данных. Это позволяет:- Избегать избыточной передачи данных (over-fetching);
- Устранять множественные запросы для сбора связанных сущностей (N+1 problem);
- Динамически адаптировать ответ под нужды клиента.
Однако GraphQL требует более сложной серверной логики и тщательного контроля за сложностью запросов (защита от злонамеренных или рекурсивных запросов).
-
gRPC-сервисы
Разработаны Google как высокопроизводительная система удалённых вызовов на основе протокола HTTP/2 и бинарного формата сериализации Protocol Buffers. Характеризуются:- Строгой контрактностью через
.proto-файлы; - Поддержкой потоковой передачи данных;
- Высокой производительностью и низкой задержкой;
- Межъязыковой совместимостью.
gRPC активно используется во внутренней микросервисной архитектуре, особенно в облачных и высоконагруженных системах.
- Строгой контрактностью через
По модели взаимодействия
- Синхронные веб-сервисы: клиент блокируется до получения ответа. Это типично для REST и SOAP.
- Асинхронные веб-сервисы: клиент получает подтверждение приёма запроса, а результат доставляется позже — через callback, webhook, очередь сообщений или событийную шину. Такие модели характерны для интеграций длительных операций (например, обработка видео, генерация отчётов).
По степени детерминированности
- Идемпотентные сервисы: повторный вызов с теми же параметрами не изменяет состояние системы (например, GET-запросы в REST).
- Неидемпотентные сервисы: каждый вызов может приводить к изменению состояния (например, POST-запросы на создание сущности).
По области применения
- Публичные (открытые) веб-сервисы — доступны любому разработчику (например, API Google Maps, OpenWeatherMap);
- Частные (внутренние) веб-сервисы — используются внутри организации или между доверенными партнёрами (например, микросервисы в архитектуре ELMA365);
- Партнёрские веб-сервисы — доступны только авторизованным внешним участникам по соглашению (например, API банка для интеграции с бухгалтерскими системами).
Запрос-ответ
Любая информационная система, будь то база данных, веб-сервис, операционная система или программный модуль, существует не в изоляции. Её предназначение — реагировать на внешние и внутренние стимулы, обрабатывать входящие данные, предоставлять информацию и управлять состоянием. В основе этой динамики лежит диалог — обмен сообщениями между двумя сущностями: инициатором действия и исполнителем. Такой диалог формализуется в модели «запрос–ответ» (англ. request–response), которая служит универсальной абстракцией для описания взаимодействия в распределённых и локальных вычислительных средах.
Модель «запрос–ответ» не ограничивается исключительно сетевыми протоколами или клиент-серверными архитектурами. Она пронизывает все уровни программного стека: от системных вызовов в ядре операционной системы до вызовов методов в объектно-ориентированном коде, от SQL-запросов к СУБД до HTTP-запросов между клиентом и сервером. Всё это — проявления единой логической структуры, где одна сторона формулирует требование, а другая — предоставляет результат, подтверждение или ошибку. Именно эта структура обеспечивает предсказуемость, управляемость и композиционность взаимодействий.
Далее последовательно рассматриваются ключевые компоненты этой модели: понятие запроса, его функциональное и семантическое содержание, а также сущность ответа — как реакции на запрос, несущей информацию о результатах обработки и состоянии системы.
1. Концепция запросов: определение и назначение
Запрос — это формализованное сообщение, инициируемое одной сущностью (инициатором, клиентом, вызывающей стороной) с целью получения информации, выполнения действия или изменения состояния другой сущности (получателя, сервера, исполнителя). Запрос выражает намерение: он несёт в себе интенциональное содержание — то, что инициатор хочет достичь.
Важно подчеркнуть: запрос сам по себе не гарантирует выполнения действия. Он представляет собой предложение к взаимодействию, подчинённое протоколу, контракту или интерфейсу, который определяет допустимые формы запроса, их семантику и условия обработки. Например, HTTP-запрос к веб-серверу содержит метод (GET, POST и т.д.), URI, заголовки и, при необходимости, тело; все эти элементы должны соответствовать спецификации протокола и ожиданиям получателя. Аналогично, SQL-запрос формулируется на декларативном языке, подчиняющемся грамматике и логике реляционной алгебры.
Функционально запрос выполняет три ключевые роли:
- Спецификация действия: запрос однозначно указывает, какое действие должно быть выполнено — выборка данных, запись, обновление, вычисление, запуск процедуры и т.п.
- Параметризация контекста: запрос содержит данные, необходимые для выполнения действия — аргументы функции, идентификаторы ресурсов, фильтры, учётные данные и пр.
- Установление контракта: форма и содержание запроса определяют ожидаемый формат ответа, уровень детализации, возможные ошибки и поведение в исключительных ситуациях.
Запрос может быть синхронным (инициатор ожидает ответа до продолжения работы) или асинхронным (инициатор продолжает выполнение, а ответ обрабатывается позже, например, через коллбэк, промис или очередь сообщений). Однако даже в асинхронных системах логическая связь «запрос → ответ» сохраняется — через корреляционные идентификаторы, токены или другие механизмы сопоставления.
Таким образом, запрос — это не просто передача данных, а акт коммуникации с чёткой прагматической направленностью. Он служит основой для декомпозиции сложных систем на модули, которые взаимодействуют через чётко определённые интерфейсы, обеспечивая слабую связанность, тестируемость и масштабируемость архитектур.
2. Что такое запрос: структура и семантика
Запрос — это структурированное представление намерения, закодированное в соответствии с принятым протоколом или интерфейсом. Его структура варьируется в зависимости от уровня абстракции, но всегда включает следующие компоненты:
- Идентификатор операции — указывает, какое действие запрашивается. Это может быть имя метода (
calculateTax), HTTP-метод (PUT), SQL-ключевое слово (SELECT), системный вызов (read) и т.п. - Контекст адресации — определяет, к какому ресурсу или сущности относится запрос. Примеры: URL (
/api/users/42), путь к файлу (/etc/passwd), имя таблицы (employees), объект в памяти. - Параметры — дополнительные данные, уточняющие действие: аргументы функции, фильтры, заголовки, тело сообщения, токены авторизации.
- Метаданные — информация, не относящаяся напрямую к логике операции, но необходимая для её корректной обработки: версия протокола, кодировка, язык предпочтения, идентификатор сессии, временные метки.
Семантически запрос всегда интерпретируется в контексте получателя. Один и тот же запрос, отправленный разным системам, может быть обработан по-разному — или отклонён, если получатель не поддерживает запрашиваемую операцию. Это подчёркивает, что запрос не обладает абсолютным смыслом, а получает его только в рамках установленного контракта взаимодействия.
Например, HTTP-запрос DELETE /resource/123 семантически означает «удалить ресурс с идентификатором 123», но только если сервер реализует такую операцию и имеет соответствующие права. Если ресурс не существует, сервер может вернуть 404 Not Found; если у клиента нет прав — 403 Forbidden. Таким образом, запрос задаёт намерение, но его реализация зависит от состояния и политики системы-получателя.
Важно также различать императивные и декларативные запросы. Императивный запрос описывает как выполнить действие (например, вызов функции с последовательными шагами), тогда как декларативный — что должно быть получено (например, SQL-запрос: «верни всех пользователей старше 18 лет»). Декларативный подход делегирует исполнение деталям реализации, что повышает абстракцию и гибкость.
API
API и SDK
+Подписка на API
Человек общается с компьютером через ввод и вывод - соответствующие устройства. А устройство, точнее, его компоненты между собой, общаются через череду сигналов. Эти сигналы структурируются в наборы данных, которые отправляются пакетами по протоколам. Но как программы друг друга понимают? Ответ - при помощи единообразия, в виде API.
API (Application Programming Interface) — это набор правил, методов и инструментов, позволяющих различным программам или сервисам взаимодействовать друг с другом. Можно привести в пример реальную жизнь - когда вы приходите в ресторан, вы не говорите напрямую поварам свои пожелания - к вам подходит официант, предоставляет меню с возможным ассортиментом, вы выбираете нужный, даёте указания официанту, который и действует аналогично API - посредник между вами и кухней.
API обычно состоит из:
- Точек доступа (endpoints, эндпоинты) — URL, по которым можно обращаться.
- Методов HTTP — GET, POST, PUT, PATCH, DELETE и др.
- Параметров запроса — пути, строка запроса (query string), заголовки, тело.
- Формата данных — JSON, XML, Protobuf и т.д.
- Документации — описание возможностей, примеры использования, ограничения.
SDK (Software Development Kit) — это набор готовых библиотек, инструментов и примеров кода, предназначенных для работы с определённым API. Используется тогда, когда хочется не писать HTTP-запросы вручную, а использовать удобный интерфейс на своём языке. К примеру, Telegram предоставляет такой набор инструментов, благодаря чему на стороне сервера нужно лишь подключить библиотеку, указать токен и использовать готовые методы для работы без необходимости расписывать логику базовых действий, к примеру, отправки сообщений. SDK скрывает сетевые детали и предоставляет простой интерфейс.
REST
REST API (Representational State Transfer) является архитектурным стилем, использующем стандартные HTTP-методы. Это самый распространённый подход для реализации веб-сервисов - можно просто определить эндпоинт, методы, параметры, формат и разработать серверный бэкенд-код, который будет «принимать» запросы и «отвечать» на них. На стороне клиента проблем ещё меньше - там просто нужно, к примеру, сделать кнопку, которая будет формировать запрос и отправлять его по эндпоинту.
Он основан на следующих принципах:
- Стандартные методы HTTP.
- Ресурсо-ориентированная адресация (URL как ресурсы).
- Отсутствие состояния (stateless).
- Поддержка разных форматов данных (обычно JSON или XML).
REST (Representational State Transfer) — это архитектурный стиль для создания веб-сервисов, основанный на использовании HTTP-протокола. REST API предоставляет набор правил для взаимодействия между клиентом и сервером через стандартные HTTP-методы.
Этот подход лучше использовать для простых CRUD-операций, и если нужно разработать API быстро, без лишней настройки.
Каждый ресурс имеет уникальный URL (Uniform Resource Locator), а данные отправляются, как правило, в формате JSON или XML. Каждый запрос содержит всю необходимую информацию для его обработки. Сервер не хранит состояние клиента между запросами. Чуть позже мы углубимся в API и REST.
Документацией REST можно считать документацию HTTP.
Стандартные методы HTTP, используемые в REST:
- GET — получение данных.
- POST — создание нового ресурса.
- PUT/PATCH — обновление существующего ресурса.
- DELETE — удаление ресурса.
Как создать свой REST API?
- Определить, какие данные будут передаваться.
- Определить, какие операции нужно поддерживать (CRUD: Create, Read, Update, Delete).
- Определить, кто будет использовать API (фронтенд, мобильное приложение, другие сервисы).
- Выбрать и определить базовый путь, например, /api/v1.
- Для каждого типа данных определить URL-пути:
- GET /users – получить список пользователей
- GET /users/123 – получить пользователя с ID 123
- POST /users – создать нового пользователя
- PUT /users/123 – обновить пользователя
- DELETE /users/123 – удалить пользователя
- Определить необходимость и добавить параметры запроса - фильтрация, сортировка, пагинация.
- Определить формат обмена данными (обычно JSON).
- Определить структуру запросов и ответов, к примеру:
// Пример запроса
{
"name": "John",
"email": "john@example.com"
}
// Пример ответа
{
"id": 123,
"name": "John",
"created_at": "2025-04-05T10:00:00Z"
}
- Настроить маршруты (роутинг) - сопоставить URL + HTTP-метод → обработчик.
- В обработчиках нужно написать возможности:
- чтения входящих данных из заголовков, строки запроса или тела;
- проверку данных (валидацию);
- обращение к БД или другому источнику данных (например, файл);
- формирование ответа - статус, заголовки, тело;
- обработка ошибок.
Обычно в готовых SDK уже имеются некоторые написанные решения, порой можно просто пользоваться имеющимися свойствами и методами объектов.
- Добавить авторизацию (если нужна, но очевидно она всегда нужна для безопасности) - JWT, OAuth, API ключи. По возможности, кстати, нужно придерживаться и иных мер безопасности - использование HTTPS, ограничение доступа по CORS, валидация данных и логирование действий.
- Задокументировать, указав описание всех эндпоинтов, примеры запросов и ответов, описание кодов и ошибок. Для этого можно использовать Open API / Swagger.
- Проверять работу всех методов можно через Postman, curl, Swagger UI.
- После тестирования, сервис разворачивается на бэкенд-сервере, допустим на хостинге, и когда будет определен хост, можно будет уже отправлять запросы. До этого момента, на этапе тестирования, его можно выполнять на локальной машине.
Итого:
- клиент отправляет HTTP-запрос на конкретный URL;
- сервер определяет маршрут и вызывает функцию-обработчик;
- обработчик получает данные, может взаимодействовать с БД или даже другими API;
- сервер формирует HTTP-ответ и отправляет его обратно клиенту.

REST — это стиль, а не строгий протокол, может быть реализован на любом языке программирования, легко масштабируется, хорошо документируется.
Postman и тестирование API
Postman — это платформа для работы с API, которая позволяет отправлять HTTP-запросы вручную, писать автотесты для проверки ответов, создавать коллекции запросов, документировать API, запускать mock-серверы и устанавливать мониторинг, работать в команде через облачное хранилище.
HTTP-клиент поддерживает все HTTP-методы (GET, POST, PUT, PATCH, DELETE и др.). Работа с заголовками и телом в Postman включает возможность полной настройки для запроса всех деталей. Вообще, возможностей в Postman очень много, однако для начала важно научиться именно работать с API и запросами.
В интерфейсе есть боковая панель с коллекциями, историей запросов, рабочими пространствами, а также главное окно с URL, методом, вкладками параметров, заголовков, тела, авторизации. Там же есть область просмотра ответа и кнопка отправки запросов.
Можем попробовать научиться:
- Скачайте себе Postman или откройте веб-версию, авторизуйтесь.
- Создайте коллекцию:
- Создайте запрос в этой коллекции:
- Простой GET-запрос - добавьте URL, укажите метод GET и нажмите Send:
https://jsonplaceholder.typicode.com/posts/1

В нижней части будет результат.
По такой же аналогии можно такой URL вставить в браузер и получить аналогичный JSON.
Для интереса можете поискать открытые API и попробовать поэкспериментировать с ними через Postman.
- POST-запрос с JSON немного другой, нужно будет указать метод POST, URL, заголовки и в Body выбрать raw - JSON:
https://jsonplaceholder.typicode.com/posts
добавить в Content-Type: application/json

{
"title": "testtitle",
"body": "testbody",
"userId": 1
}
Отправьте запрос и убедитесь, что сервер вернул статус 201 Created.

Коллекции - это группы связанных запросов. Вы можете группировать их, распределять как удобно, делиться с коллегами. По сути, они хранятся в JSON-файле.
Postman можно использовать в терминале или CI/CD через Newman — CLI-утилиту.
curl же в принципе представляет собой утилиту командной строки, используемой в скриптах, CI/CD и не требует установок. Здесь всё формируется просто:

Открывается командная строка, пишется команда curl, и указывается адрес - тогда выполняется GET запрос. Кстати говоря, в PowerShell в Windows curl всего лишь псевдоним для Invoke-WebRequest, и он не использует тот же синтаксис, что и настоящий curl в Linux/macOS или Windows Terminal. Поэтому можно наткнуться на ошибки если пытаться работать с curl в Windows.
К примеру, в Linux GET выполняется через curl -X GET:
curl -X GET "https://jsonplaceholder.typicode.com/posts/1"
PowerShell пытается найти параметр -X, но у командлета Invoke-WebRequest такого параметра нет, поэтому вы получите ошибку. В Windows лучше использовать явно Invoke-WebRequest, ведь к примеру, с POST уже это не прокатит:
Invoke-WebRequest -Uri "https://jsonplaceholder.typicode.com/posts" `
-Method Post `
-ContentType "application/json" `
-Body '{"title":"testtitle","testbody":"bar","userId":1}'
Такой запрос аналогичен предыдущему в Postman, и при успехе будет 201.
curl-скрипт можно создать и запускать, что позволит экспериментировать с нагрузками, планировать задачи и выполнять работу без использования кода и разработки полноценных веб-служб.
Другие API
А как же другие API?
GraphQL API запрашивает только нужные данные, гибко управляя структурой ответа, используется для SPA, микросервисов, сложных данных.
SOAP API более старый протокол с жёсткой структурой, основанный на XML. Его можно встретить в устаревших корпоративных системах.
gRPC API высокопроизводительный (ведь там RPC-протокол), работает поверх HTTP/2, использует Protobuf. В высоконагруженных системах с микросервисами можно часто встретить такой стиль.
WebSocket API, как мы уже не раз отметили, использует двустороннее постоянное соединение.
SSE (Server-Sent Events) использует одностороннюю передачу данных от сервера к клиенту - новости, уведомления, мониторинг.
OAuth 2.0 API — это протокол авторизации, который позволяет приложениям получать ограниченный доступ к ресурсам пользователя без необходимости знать его пароль. К примеру, это авторизация через Google/Facebook, подключение к Google Drive или Dropbox, работа с банковскими API. OAuth 2.0 использует токены , такие как:
- access_token — временный ключ для доступа к ресурсам
- refresh_token — для получения нового access_token
Front API — это не общепринятый термин, но его можно интерпретировать как API, которое используется для взаимодействия с фронтендом (клиентской частью) приложения. В более широком смысле это может означать:
- API для клиентских приложений - предоставление данных и функциональности для веб-приложений, мобильных приложений или десктопных клиентов.
- REST/GraphQL API - часто такие API используются для передачи данных между сервером и клиентом.
Кстати говоря о фронте, следует отметить, что как раз для работы с API в JavaScript используют метод fetch():
fetch('/api/user/profile', {
method: 'GET',
headers: { Authorization: 'Bearer <token>' }
})
fetch() — это встроенный в браузер метод , позволяющий отправлять HTTP-запросы к серверу и получать данные без перезагрузки страницы. Он возвращает Promise , который разрешается в объект ответа (Response), а затем можно обработать тело ответа (например, как JSON или текст). Синтаксис прост - fetch(input, init). input это URL, по которому делается запрос (строка) или объект Request, а init (необязательный) это объект с настройками запроса: метод, заголовки, тело и т.д.
После вызова fetch(), вы получаете объект Response.
Основные свойства Response:
- .ok — возвращает true, если статус 200–299.
- .status — HTTP-статус ответа (например, 200, 404).
- .statusText — текстовое описание статуса (например, "OK", "Not Found").
- .headers — объект Headers, содержащий заголовки ответа.
- .url — фактический URL ответа (может отличаться от запрошенного при редиректах).
Методы для получения тела:
- .json() — парсит тело как JSON.
- .text() — возвращает тело как строку.
- .blob() — возвращает как Blob (например, изображения).
- .formData() — возвращает как FormData.
- .arrayBuffer() — возвращает как массив ArrayBuffer.
fetch() подчиняется политике CORS (Cross-Origin Resource Sharing), если сервер не разрешает кросс-доменные запросы, браузер блокирует их, а для авторизации может потребоваться установка заголовков или использование credentials.
Web API — это общий термин, обозначающий API, доступные через веб-интерфейс. Это могут быть как серверные API (например, REST, GraphQL), так и клиентские API (например, браузерные API).
Основные типы Web API:
Серверные API :
- RESTful API: стандартный подход к созданию веб-сервисов.
- GraphQL API: гибкий запрос данных с возможностью выбора полей.
- SOAP API: устаревший протокол для веб-сервисов.
Клиентские API :
- DOM API: управление HTML-документами в браузере.
- Fetch API: выполнение HTTP-запросов из браузера.
- Geolocation API: получение географических данных пользователя.
Fluent API — это стиль программирования, при котором методы возвращают объект, позволяя «цеплять» вызовы методов друг за другом. Используется в ORM, билдерах SQL, тестовых фреймворках. Этот подход часто используется для создания удобного и читаемого кода.
FastAPI — это современный веб-фреймворк для создания API на Python. Он известен своей высокой производительностью, простотой использования и поддержкой асинхронного программирования. Основан на на Starlette и Pydantic, что делает его одним из самых быстрых фреймворков.
Чит-лист FastAPI - https://cheatsheets.zip/fastapi
Starlette — это лёгкий и быстрый веб-фреймворк для Python, предназначенный для создания асинхронных веб-приложений и API. Он является основой таких проектов, как FastAPI , и известен своей производительностью и гибкостью.
Pydantic — это библиотека Python для валидации данных и управления конфигурацией с использованием аннотаций типов. Она автоматически проверяет данные на соответствие ожидаемым типам и структурам.
SignalR — это библиотека для ASP.NET Core, которая позволяет реализовать реальное взаимодействие между клиентом и сервером. Она поддерживает двустороннюю связь через WebSocket, Server-Sent Events (SSE) и Long Polling. Именно оно используется для чатов, онлайн-игр, обновлений.
Long Polling — это техника для реализации асинхронного взаимодействия между клиентом и сервером в веб-приложениях. Она позволяет клиенту ожидать новые данные от сервера, не отправляя постоянные запросы.
Как работает:
- Клиент отправляет HTTP-запрос на сервер.
- Сервер держит соединение открытым до тех пор, пока не появятся новые данные или истечет таймаут.
- Как только данные доступны, сервер отправляет ответ, и клиент сразу же отправляет новый запрос.
Каждая программа, которая поддерживает какой-то свой метод взаимодействия, может предоставлять свой интерфейс, и как правило, он будет характерен именно для взаимодействия соответствующего продукта - Kubernetes API, Telegram API, Windows API, WhatsApp API, Google Maps API, Twitter/X API и прочие.
HTTP
Структура HTTP-запроса
HTTP-запрос состоит из трёх частей - стартовая строка, заголовок и тело запроса.
Стартовая строка указывает метод, путь и версию протокола. Пример:
GET /posts/1 HTTP/1.1
Стартовая строка - это самая первая строка запроса, которая формируется по шаблону:
<Метод> <Путь> <Версия протокола>
Методом называется действие, которое хочет выполнить клиент (GET, POST, PUT, PATCH, DELETE и другие).
Путь - это URL-адрес на сервере, указывающий, к какому ресурсу обращается клиент.
Версия протокола - это версия HTTP, которую использует клиент (HTTP/1.1, HTTP/2, HTTP/3).
Заголовок содержит дополнительную информацию о запросе. Это блок метаданных, передаваемых вместе с запросом. Заголовки содержат информацию о клиенте, теле запроса, авторизации, формате данных и многое другое.
Заголовок формируется по формату:
<Имя заголовка>: <Значение>
Заголовки бывают общие, кастомные, заголовки запроса и заголовки сущности. Мы отдельно их рассмотрим.
Тело запроса является необязательным и используется для методов POST, PUT, PATCH. Тело содержит полезные данные, отправляемые серверу. К примеру, JSON:
{
"title": "foo",
"body": "bar",
"userId": 1
}
Формат данных в теле определяется через заголовок Content-Type, HTTP-заголовок, который указывает тип содержимого в теле запроса или ответа. Пример:
Content-Type: text/html; charset=UTF-8
Это означает, что тело сообщения содержит HTML-документ, использующий кодировку UTF-8. А для JSON указывается application/json. Важно понимать, что путь в запросах представляет собой часть URI после домена, которая указывает на конкретный ресурс. К примеру, если Host указан как api.example.com, а в стартовой строке указан путь как /api/users, то полный URI будет http://api.example.com/api/users. Мы же помним разницу между URL и URI?
Пути могут содержать:
- параметры пути - /users/123
- параметры строки запроса (или просто параметры запроса) - ?sort=date&limit=10
Учитывая всю эту кучу информации, нам понадобится шаблон для составления сложных запросов, который бы включал все ключевые элементы:
<МЕТОД> <ПУТЬ> <ВЕРСИЯ ПРОТОКОЛА>
Host: <ХОСТ>
[ЗАГОЛОВОК 1]: <ЗНАЧЕНИЕ 1>
[ЗАГОЛОВОК 2]: <ЗНАЧЕНИЕ 2>
...
[ЗАГОЛОВОК N]: <ЗНАЧЕНИЕ N>
<ТЕЛО ЗАПРОСА (необязательно)>
Такой шаблон может пригодиться при тестировании API вручную, например, через Telnet, Netcat или текстовый файл, а также при написании скриптов.
Для простоты лучше использовать Postman и curl - они автоматически добавляют нужные заголовки и корректно формируют тело.
Когда и какие версии HTTP использовать?
HTTP/0.9 - простая версия 1991 года выпуска. Это очень простой протокол, там есть только GET, без заголовков и статус-кодов.
HTTP/1.0 выпущена в 1996 году, туда как раз и были добавлены заголовки, коды состояния и MIME-типы.
HTTP/1.1 выпущен в 1999 году и используется до сих пор. Здесь добавили поддержку keep-alive (persistent connections), pipelining, хостинга на одном IP.
Keep-Alive — это механизм, позволяющий повторно использовать одно TCP-соединение для нескольких HTTP-запросов и ответов. Просто добавляется заголовок Connection: keep-alive. Если он не указан, в HTTP/1.1 добавляется по умолчанию, чтобы его отключить надо указать close. Это уменьшает задержку, связанную с установкой новых TCP-соединений, ускоряет загрузку страницы за счёт повторного использования соединения, и экономит ресурсы сервера.
Pipelining — возможность отправки нескольких HTTP-запросов подряд по одному соединению без ожидания ответа на предыдущий, что ускоряет работу клиент-серверного взаимодействия. Но не все серверы его поддерживают, и требуется строгое соблюдение порядка ответов, при работе с прокси или брандмауэрами могут быть проблемы. В HTTP/2 pipelining заменён более мощным механизмом — мультиплексированием.
HTTP/2 появился в 2015, добавив бинарный протокол, мультиплексирование, сжатие заголовков, сервер push. В отличие от текстового формата HTTP/1.x, в HTTP/2 используется бинарный формат передачи данных, что позволяет более эффективно парсить данные, уменьшает вероятность ошибок при чтении запросов и ответов, а также использовать новые функции, такие как потоки и мультиплексирование.
Мультиплексирование - одна из ключевых особенностей HTTP/2, когда клиент может отправлять несколько запросов по одному TCP-соединению, не дожидаясь ответа на предыдущий. Это устраняет проблему последовательной загрузки ресурсов, снижает задержку (latency) и позволяет браузеру быстрее загружать страницы.
Заголовки часто повторяются между запросами. В HTTP/2 используется сжатие заголовков через алгоритм HPACK, который снижает объём данных, особенно при множестве небольших запросов.
Сервер Push подразумевает, что сервер может предварительно отправить клиенту ресурсы, которые он ещё не запрашивал, но, возможно, потребуется в будущем (например, CSS или JS).
HTTP/3 выпущен в 2022, работает поверх UDP через QUIC, устраняет head-of-line blocking. Если проще, протокол QUIC использует UDP вместо TCP, что обеспечивает быстрое восстановление соединений при смене сети (например, с Wi-Fi на мобильную сеть), обеспечивать шифрование по умолчанию. А устранение head-of-line blocking подразумевает, что если одно сообщение теряется, это не блокирует все остальные.
Пример сложного HTTP-запроса:
PATCH /api/v2/users/12345/preferences HTTP/2
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx
Content-Type: application/json
Accept: application/vnd.mycompany.api.v2+json
Accept-Language: en-US,en;q=0.9,ru;q=0.8
If-Match: "a1b2c3d4"
X-Request-ID: 7c6d3a1b-9f0e-4d2a-bcde-f123456789ab
Cache-Control: no-cache
{
"theme": "dark",
"notifications": {
"email": true,
"sms": false
},
"preferences": {
"language": "en",
"currency": "USD",
"units": "metric"
},
"favorite_items": [101, 102, 105]
}
Давайте разберём.
- Стартовая строка здесь будет такой:
PATCH /api/v2/users/12345/preferences HTTP/2
PATCH - метод, используется для частичного обновления ресурса.
/api/v2/users/12345/preferences — путь к ресурсу на сервере.
HTTP/2 — версия протокола. В отличие от HTTP/1.1, это бинарный протокол с поддержкой мультиплексирования.
- Заголовок здесь будет часть запроса, от Host до Cache-Control.
Host: api.example.com указывает домен, на который отправляется запрос. Особенно важно при использовании виртуального хостинга.
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx - это токен авторизации в формате JWT (JSON Web Token). Используется для идентификации пользователя или сервиса.
Content-Type: application/json указывает, что тело запроса содержит данные в формате JSON.
Accept: application/vnd.mycompany.api.v2+json это запрашиваемый формат ответа. Здесь указан кастомный MIME-тип для API версии 2 от компании mycompany.
Accept-Language: en-US,en;q=0.9,ru;q=0.8 это языковые предпочтения клиента. Сервер может выбрать язык ответа в зависимости от доступных вариантов.
If-Match: "a1b2c3d4" это условный заголовок. Сервер выполнит запрос только если ETag ресурса совпадает с этим значением. Используется для оптимистической блокировки (preventing race conditions).
X-Request-ID: 7c6d3a1b-9f0e-4d2a-bcde-f123456789ab это кастомный заголовок, используемый для логгирования и трассировки запроса на стороне сервера.
Cache-Control: no-cache это инструкция клиенту и промежуточным серверам не использовать закэшированный ответ без проверки актуальности.
- Тело запроса здесь будет JSON-объектом, содержащим пользовательские настройки интерфейса (тема), уведомления - включены ли email или SMS, предпочтения (язык, валюта, единицы измерения), список любимых элементов (ID товаров).
Приведенный в примере запрос является сложным, так как здесь используется редкий метод PATCH, версия HTTP/2 (бинарный протокол, мультиплексирование и другие продвинутые возможности), авторизация через Bearer Token, кастомный Accept тип и условный запрос.
Bearer Token это механизм авторизации, при котором клиент предоставляет токен (к примеру, через OAuth2 или JWT), который сервер проверяет. При каждом запросе к защищённому API клиент добавляет заголовок Authorization. Сервер проверяет токен и, если он действителен, разрешает доступ. Кастомные заголовки и типы обычно начинаются с префикса X-… - хотя с 2012 года рекомендуется использовать зарегистрированные заголовки , а не X-*, так как некоторые системы могут игнорировать такие заголовки. Кастомные типы контента (MIME-типы) указываются без X, но, как выше приведено в примере, может указывать на специфический формат (application/vnd.mycompany.api.v2+json - JSON в специальной версии v2 от компании mycompany).
Условные запросы в HTTP представляют собой механизм, позволяющий выполнять запросы только при выполнении определённых условий.
| Заголовок | Назначение |
|---|---|
| If-Match | Выполнить запрос, только если ETag совпадает. |
| If-None-Match | Выполнить запрос, только если ETag НЕ совпадает. |
| If-Modified-Since | Только если ресурс был изменён после указанной даты. |
| If-Range | Используется при частичной загрузке (Range requests). |
Условные запросы могут предотвратить конфликты при параллельном редактировании, экономят трафик (например, не отправляют данные, если клиент уже имеет актуальную версию), позволяют организовать кэширование и частичную синхронизацию. E-Tag - это уникальный идентификатор текущей версии ресурса.
Структура HTTP-ответа
HTTP-ответ содержит тоже три составные части - статус-строка, заголовки и тело ответа.
Статус-строка содержит версию протокола, статусный код и фразу (например, 200 OK). К примеру:
HTTP/2 200 OK
Заголовки содержат метаданные ответа.
Тело ответа содержит фактические данные, например, HTML-страница или данные в JSON.
Пример сложного ответа от сервера:
HTTP/2 200 OK
Content-Type: application/vnd.mycompany.api.v2+json
Content-Language: en-US
ETag: "z9y8x7w6"
X-Request-ID: 7c6d3a1b-9f0e-4d2a-bcde-f123456789ab
Cache-Control: no-store
Vary: Accept-Encoding, Accept-Language
Server: MyCompany-API-Gateway
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
"status": "success",
"message": "Preferences updated successfully",
"data": {
"user_id": 12345,
"theme": "dark",
"notifications": {
"email": true,
"sms": false
},
"preferences": {
"language": "en",
"currency": "USD",
"units": "metric"
},
"favorite_items": [101, 102, 105],
"updated_at": "2025-04-05T14:30:00Z"
},
"meta": {
"version": "v2",
"server_time": "2025-04-05T14:30:00Z",
"request_id": "7c6d3a1b-9f0e-4d2a-bcde-f123456789ab"
}
}
Здесь в статус-строке указана версия протокола HTTP/2, код успешного выполнения запроса (200) и ОК - фраза, описывающая результат. В данном случае сервер успешно обработал PATCH-запрос и обновил часть данных пользователя.
Content-Type указывает, что формат данных в теле ответа: application/vnd.mycompany.api.v2+json — специальная версия API компании. Content-Language говорит, что язык содержимого en-US.
ETag это специальный тег, который является уникальным идентификатором текущей версии ресурса. Используется для условных запросов (If-Match, If-None-Match).
X-Request-ID имеет тот же ID, что был отправлен клиентом — используется для логгирования и трассировки.
Cache-Control: no-store говорит о том, что сервер запрещает сохранять этот ответ в кэше.
Vary говорит прокси-серверам, какие заголовки влияют на выбор правильного ответа. Здесь учитываются Accept-Encoding и Accept-Language. Server содержит информацию о сервере.
Strict-Transport-Security обязывает браузер использовать HTTPS, защищая от downgrade-атак.
X-Content-Type-Options: nosniff запрещает браузеру пытаться угадать MIME-тип.
X-Frame-Options: DENY защищает от clickjacking-атак, запрещая отображать страницу в <iframe>. Мы же помним, что такое iframe?
С телом ответа проще - тут JSON, который содержит общий статус операции, сообщение, данные, метаданные.
HTTP-заголовки
Давайте рассмотрим HTTP-заголовки.
- Общие заголовки (General Headers). Заголовки, которые относятся к всему сообщению, но не связаны ни с запросом, ни с ответом напрямую.
| Заголовок | Описание |
|---|---|
| Cache-Control | Управление кэшированием |
| Connection | Управление сетевым соединением (keep-alive, close) |
| Date | Дата и время создания сообщения |
| Pragma | Совместимость с устаревшими кэшами |
| Trailer | Указывает, какие заголовки будут отправлены после тела сообщения |
| Transfer-Encoding | Способ кодирования передачи тела сообщения (например, chunked) |
| Upgrade | Предложение переключиться на другую версию протокола |
| Via | Используется прокси для указания пути |
| Warning | Информация о проблемах при обработке сообщения |
- Заголовки запроса (Request Headers). Передаются клиентом (браузером) серверу и содержат информацию о самом запросе, клиенте или желаемом ответе.
| Заголовок | Описание |
|---|---|
| Accept | Какие типы контента клиент может обработать |
| Accept-Charset | Поддерживаемые клиентом кодировки |
| Accept-Encoding | Поддерживаемые методы сжатия (gzip, deflate) |
| Accept-Language | Языковые предпочтения клиента |
| Authorization | Данные аутентификации |
| Cookie | Клиентские cookies |
| Expect | Ожидание определённого ответа от сервера |
| From | Email пользователя (редко используется) |
| Host | Имя хоста (обязательный заголовок в HTTP/1.1) |
| If-Match, If-None-Match | Условные запросы |
| If-Modified-Since | Проверка изменения ресурса |
| Max-Forwards | Ограничение числа прыжков через прокси |
| Proxy-Authorization | Авторизация перед прокси |
| Range | Запрос части ресурса |
| Referer | Откуда был сделан запрос |
| TE | Какие расширения передачи поддерживает клиент |
| User-Agent | Информация о браузере и ОС |
- Заголовки ответа (Response Headers). Устанавливаются сервером и содержат информацию о результате выполнения запроса.
| Заголовок | Описание |
|---|---|
| Accept-Ranges | Поддерживаемые диапазоны (например, bytes) |
| Age | Возраст ответа (сколько секунд прошло с момента его генерации) |
| Content-Type | Формат данных в теле ответа. |
| Content-Language | Язык содержимого. |
| ETag | Уникальный идентификатор версии ресурса. Используется для условных запросов (If-Match, If-None-Match). |
| Location | Адрес нового ресурса (часто в ответах 3xx) |
| Proxy-Authenticate | Метод аутентификации перед прокси |
| Retry-After | Когда клиент может повторить запрос |
| Server | Информация о сервере или шлюзе, который обработал запрос. |
| Set-Cookie | Установка cookie на стороне клиента |
| Strict-Transport-Security | Обязывает браузер использовать HTTPS, защищая от downgrade-атак. |
| WWW-Authenticate | Требование авторизации |
| Vary | Какие заголовки влияют на выбор закэшированной версии ответа. Здесь учитываются Accept-Encoding и Accept-Language. |
- Заголовки сущности (Entity Headers). Описывают тело сообщения (его тип, размер, кодировку и т. д.).
| Заголовок | Описание |
|---|---|
| Allow | Поддерживаемые методы |
| Content-Encoding | Способ кодирования тела (gzip, compress) |
| Content-Language | Язык содержимого |
| Content-Length | Размер тела сообщения в байтах |
| Content-Location | Альтернативное расположение ресурса |
| Content-MD5 | Контрольная сумма тела (устарел) |
| Content-Range | Диапазон передаваемых данных |
| Content-Type | MIME-тип тела сообщения |
| Content-Disposition | Как браузер должен обрабатывать содержимое (например, inline отобразит в браузере, а attachment предложит сохранить) |
| Expires | Дата истечения срока действия кэша |
| Last-Modified | Дата последнего изменения ресурса |
Content-Type состоит из типа (type) и подтипа (subtype), разделённых косой чертой (type/subtype). Их называют MIME-типы (Multipurpose Internet Mail Extensions), это типы данных, которые могут быть переданы через сеть.
К примеру - text/plain, image/jpeg, application/json. Иногда добавляются парамтеры, например, charset=utf-8, boundary=something_unique.
Есть чит-лист с MIME-типами - https://cheatsheets.zip/mime
Основные категории Content-Type:
- text/ — текстовые данные, простой текст:
| Тип | Описание |
|---|---|
| text/plain | Обычный текст без форматирования |
| text/html | HTML-документ |
| text/css | CSS-стили |
| text/javascript | JavaScript-код (устаревший, сейчас чаще используется application/javascript) |
| text/csv | Таблицы в формате CSV |
- image/ — графические изображения:
| Тип | Описание |
|---|---|
| image/jpeg | Фотографии, формат JPEG |
| image/png | Изображения с прозрачностью, PNG |
| image/gif | Анимированные/статичные GIF |
| image/webp | Современный формат от Google |
| image/svg+xml | Векторная графика в формате SVG |
- audio/ и video/ — медиафайлы
| Тип | Описание |
|---|---|
| audio/mpeg | MP3-файл |
| audio/ogg | OGG-формат аудио |
| video/mp4 | Видео в формате MP4 |
| video/webm | Видео WebM, поддерживается в браузерах |
- application/ — прикладные данные, это самый обширный тип, используется для файлов, данных в определённом формате, двоичных данных и т. д.:
| Тип | Описание |
|---|---|
| application/json | JSON-данные |
| application/xml | XML-данные |
| application/javascript | JavaScript документ |
| application/soap+xml | SOAP |
| application/xhtml+xml | XHTML документ |
| application/pdf | PDF-документ |
| application/msword | Документ Word (.doc) |
| application/vnd.openxmlformats-officedocument.wordprocessingml.document | Word .docx |
| application/octet-stream | Бинарные данные (универсальный «неизвестный» тип) |
| application/x-www-form-urlencoded | Данные формы, отправленной через POST |
| application/zip | ZIP-архив |
| application/gzip | GZIP-архив |
- multipart/ — составные сообщения, используемые, когда в одном сообщении передаётся несколько частей. Например, при загрузке файла через форму. Виды:
| Тип | Описание |
|---|---|
| multipart/form-data | Используется при загрузке файлов через HTML-формы |
| multipart/byteranges | Используется для передачи диапазонов байтов (например, при паузе в загрузке) |
- message/ — сообщения:
| Тип | Описание |
|---|---|
| message/rfc822 | Сообщение электронной почты в формате RFC 822 |
| message/http | Сообщение HTTP внутри другого HTTP-сообщения |
- model/ — моделирование: | Тип | Описание | | :--- | :---: | |model/stl |STL-файлы 3D-моделей |model/gltf+json |Формат GLTF для 3D-графики
Content-Type отсутствует, если данные передаются в URL. Такое можно наблюдать в запросах с методом GET. К примеру, здесь нет Content-Type, так как нет данных в теле:
GET /search?q=hello HTTP/1.1
Host: example.com
Основной способ отправки данных - метод POST:
POST /api/login HTTP/1.1
Content-Type: application/json
Content-Length: 45
{"username":"john","password":"secret"}
Здесь указывается метод POST, URL api/login, протокол HTTP/1.1, тип контента же представляет собой JSON-объект.
Он помогает браузеру или серверу понять, как интерпретировать данные, которые были переданы.
HTTP-методы
HTTP-методы определяют тип действия, которое клиент хочет выполнить на сервере. Основые методы:
| Метод | Описание |
|---|---|
| GET | Получить данные. Запрос данных с сервера (например, получить HTML-страницу или JSON-данные). |
| HEAD | Аналог GET, но сервер возвращает только заголовки, без тела ответа. |
| POST | Отправка данных на сервер для создания нового ресурса или выполнения действия. |
| PUT | Обновление существующего ресурса на сервере. |
| DELETE | Удаление ресурса на сервере. |
| OPTIONS | Получить поддерживаемые методы. Запрос информации о доступных методах и возможностях сервера (например, CORS). |
| PATCH | Частичное обновление ресурса (в отличие от PUT, который заменяет весь ресурс). Изменяются только указанные поля, допустим лишь часть указанную в JSON. |
| CONNECT | Используется для HTTPS-туннелирования |
| TRACE | Диагностический метод для отладки |
HTTP-статусы
HTTP-статусы указывают на результат выполнения запроса. Они делятся на группы:
- 1xx — Информационные:
- 100 Continue — Сервер получил заголовки запроса и ожидает продолжения.
- 101 Switching Protocols — Сервер согласился сменить протокол (например, на WebSocket).
- 2xx — Успешные:
- 200 OK — Запрос выполнен успешно.
- 201 Created — Ресурс успешно создан (обычно после POST).
- 204 No Content — Запрос выполнен, но ответ не содержит тела.
- 3xx — Перенаправления:
- 301 Moved Permanently — Ресурс перемещён на новый URL.
- 302 Found — Временное перенаправление.
- 304 Not Modified — Ресурс не изменился с момента последнего запроса.
- 4xx — Ошибки клиента:
- 400 Bad Request — Некорректный запрос.
- 401 Unauthorized — Необходима аутентификация.
- 403 Forbidden — Доступ запрещён.
- 404 Not Found — Ресурс не найден.
- 429 Too Many Requests — Превышено количество запросов.
- 5xx — Ошибки сервера:
- 500 Internal Server Error — Внутренняя ошибка сервера.
- 502 Bad Gateway — Неправильный ответ от вышестоящего сервера.
- 503 Service Unavailable — Сервер временно недоступен.
Чит-лист с HTTP-кодами - https://cheatsheets.zip/http-status-code
Асинхронная коммуникация
Мы уже изучали асинхронность, поэтому можем уже понять, что асинхронная коммуникация — это способ взаимодействия, при котором отправитель не ждёт немедленного ответа от получателя. Это особенно важно в распределённых системах, где синхронные вызовы могут привести к задержкам или блокировкам. При таком решении используется либо очередь, либо события. Мы их ранее рассматривали вкратце.
Примерами асинхронного взаимодействия может являться:
- SMTP, отправка электронной почты. Клиент отправляет письмо, но не ждёт подтверждения его доставки получателю.
- JMS (Java Message Service), использование очередей сообщений для передачи данных между системами.
- RabbitMQ/Kafka, брокеры
Очереди сообщений (Message Queues или MQ) подразумевает, что сообщения помещаются в очередь, и сервисы обрабатывают их по мере готовности. Примеры решений - RabbitMQ, Apache Kafka, Amazon SQS. Используется для задач, которые могут выполняться в фоновом режиме (например, отправка email).
Транспорт в асинхронной коммуникации:
- SMTP;
- AMQP;
- MQTT;
- Kafka.
SMTP (Simple Mail Transfer Protocol) — это протокол для отправки электронной почты. Он используется для передачи сообщений между почтовыми серверами или от клиента к серверу. Письмо отправляется, но доставка может занять время. Для повторной отправки в случае сбоя используются очереди.

MQTT (Message Queuing Telemetry Transport) — это лёгкий протокол для передачи данных в условиях ограниченной пропускной способности или нестабильного соединения. Он часто используется в IoT (Интернет вещей). Устройства могут подписываться на темы и получать обновления.

AMQP (Advanced Message Queuing Protocol) — это протокол для асинхронного обмена сообщениями между системами через брокеры сообщений (например, RabbitMQ). Сообщения хранятся в очередях до тех пор, пока не будут обработаны.
Apache Kafka — это платформа для потоковой передачи данных. Она позволяет системам обмениваться событиями в реальном времени. Kafka и RabbitMQ мы разберём отдельно.
Реактивная коммуникация
Реактивные взаимодействия фокусируются на обмене событиями в режиме реального времени. Системы реагируют на события по мере их возникновения, обеспечивая непрерывный поток данных.
Транспорт:
- WebSockets
- SSE
- Kafka Streams
- MQTT
WebSockets является самым распространённым представителем реактивной коммуникации, ведь устанавливается двусторонний канал связи между клиентом и сервером, который позволяет обмениваться данными в реальном времени. Это протокол для двусторонней связи между клиентом и сервером через единственный постоянный канал. После установления соединения данные передаются без дополнительных HTTP-заголовков.
Server-Sent Events (SSE) предполагает, что сервер отправляет обновления клиенту через однонаправленный канал, это протокол для однонаправленной передачи данных от сервера к клиенту через HTTP. Сервер отправляет данные клиенту, но обратная связь невозможна. Если соединение разрывается, клиент автоматически переподключается. Пример - трансляция обновлений и уведомления в реальном времени.
Event Streaming — это потоковые платформы, такие как Apache Kafka, позволяют системам подписываться на события и реагировать на них. Потоковые операторы — это инструменты для обработки потоков данных в реальном времени. Они позволяют выполнять преобразования, фильтрацию и агрегацию данных. Примеры потоковых операторов:
- Map - преобразует каждый элемент потока. Пример - увеличить все числа в потоке на 1:
stream.map(x => x + 1);
- Filter - отбирает только те элементы, кторые удовлетворяют условию. Пример - оставить только положительные числа:
stream.filter(x => x > 0);
- Reduce - агрегирует данные в один результат. Пример - подсчитать сумму всех чисел в потоке:
stream.reduce((acc, x) => acc + x, 0);
- FlatMap - преобразует каждый элемент в несколько элементов. Пример - разбить строку на слова:
stream.flatMap(sentence => sentence.split(' '));
Потоковые операторы в интеграции используются как раз в Apache Kafka Streams. На практике это обработка событий в реальном времени (например, подсчёт количества кликов пользователей).
Kafta и MQTT - не только асинхронные протоколы, но и реактивные.
Реактивные системы обеспечивают мгновенный обмен данными, и они подходят для работы с большим количеством событий и пользователей. Такое можно встретить в чатах, онлайн-играх, биржевых платформах, системах мониторинга.
Брокеры сообщений
Вы наверняка сталкивались с термином «брокер», используемом при сделках на бирже? А теперь представьте, что между системами нужно обеспечить асинхронную доставку большого количества сообщений, через посредника-агента.
Брокер сообщений — это программное обеспечение или система, которая управляет обменом данными между приложениями, сервисами или системами. Некоторые считают брокеры сообщений как архитектурные шаблоны в распределённых системах, но основна задача брокеров - преобразовать сообщение источника в сообщение приёмника.
Брокер выступает в роли посредника, который принимает сообщения от «производителей» (producers) и передаёт их «потребителям» (consumers). Это позволяет организовать асинхронную связь между компонентами системы.
Производитель отправляет сообщение в брокер и продолжает свою работу, не дожидаясь ответа от потребителя, а брокер гарантирует доставку сообщений даже в случае сбоев (например, через очереди и подтверждения) и позволяет распределять нагрузку между несколькими потребителями, что упрощает масштабирование.
Среди брокеров различают RabbitMQ (модель очередей), Apache Kafka (модель топиков), ActiveMQ (классический брокер сообщений с поддержкой JMS), IBM MQ и Redis (который также используется для кэширования).
Потребители нуждаются в данных для выполнения своих функций - учёт, отслеживание, вычисления, мониторинг, проверки. Данные передаются как раз в виде структурированного пакета данных - сообщения. В RabbitMQ/IBM MQ/ActiveMQ их так и называют - «сообщения», а в Apache Kafla называются «топики».
Мы рассмотрим RabbitMQ и Kafka по отдельности. Для начала давайте разграничим их в виде таблицы отличий:
| Критерий | RabbitMQ | Kafka |
|---|---|---|
| Архитектура | Основана на очередях (queues). | Основана на топиках (topics) с партициями (partitions). |
| Модель работы | Производитель → Обменник (Exchange) → Очередь → Потребитель. | Производитель → Топик → Партиция → Потребитель. |
| Упорядоченность | Гарантируется порядок в пределах одной очереди. | Гарантируется порядок только внутри одной партиции. |
| Состояние данных | Сообщения хранятся до доставки или истечения времени хранения. | Сообщения хранятся на диске в течение заданного времени (например, 7 дней). |
| Производительность | До десятков тысяч сообщений/секунду. | До миллионов сообщений/секунду. |
| Задержки | Низкие задержки благодаря прямой передаче через очереди. | Задержки выше из-за партиционирования и логической структуры. |
| Ресурсы | Требует меньше ресурсов для небольших нагрузок. | Требует больше памяти и дискового пространства. |
| Масштабируемость | Масштабируется за счёт добавления брокеров, но сложнее настроить кластер. | Легко масштабируется за счёт добавления брокеров и партиций. |
| Гарантия доставки | Гарантированная доставка каждого сообщения. | Доставка "хотя бы один раз" (at-least-once delivery). |
| Маршрутизация | Поддерживает сложные правила маршрутизации через обменники (exchanges). | Маршрутизация ограничена топиками и партициями. |
| Веб-интерфейс | Встроенный веб-интерфейс (RabbitMQ Management). | Нет встроенного интерфейса, но можно использовать сторонние инструменты. |
| Сценарии использования | Фоновые задачи, микросервисы, системы уведомлений. | Потоковая аналитика, логирование, мониторинг, IoT. |
| Примеры задач | Отправка email, обработка заказов, рассылка уведомлений. | Сбор и анализ логов, мониторинг событий, обработка данных в реальном времени. |
RabbitMQ
RabbitMQ — это популярный брокер сообщений (Message Broker), который реализует протокол AMQP. Он используется для асинхронного обмена данными между приложениями через очереди. RabbitMQ обеспечивает надёжную доставку сообщений, масштабируемость и гибкость. Как почтовое отделение, точно доставляющее по адресам.
Официальный сайт - https://www.rabbitmq.com/
Сообщения хранятся в очередях до тех пор, пока не будут обработаны. Производитель отправляет сообщение в очередь, а потребитель забирает его позже.

Порой сервисы нужно отделить друг от друга, обеспечить доставку сообщений между ними даже при падении системы, и при этом управлять нагрузкой и очередями задач. Для этого «кролик» использует простой принцип:
- Производитель отправляет сообщение.
- Обменник получает сообщение и решает, куда его направить.
- Сообщение помещается в очередь.
- Потребитель забирает сообщение из очереди.
Сообщение гарантированно не потеряется: оно остаётся в очереди, пока не будет подтверждено потребителем.
RabbitMQ использует модель «производитель-потребитель» с промежуточным хранилищем — очередью:
- Producer (Производитель) отправляет сообщения в RabbitMQ, может быть любым приложением или системой;
- Exchange (Обменник) принимает сообщения от производителя и определяет, в какую очередь поместить сообщение, исходя из правил маршрутизации;
- Queue (Очередь) хранит сообщения до тех пор, пока они не будут обработаны потребителем.
- Consumer (Потребитель) забирает сообщения из очереди и обрабатывает их согласно логике приложения.

Производителем может быть веб-сервер, сервис оплаты, IoT-устройство - это приложение, которое отправляет сообщения в RabbitMQ.
Сообщение - это набор данных. Оно не попадает сразу в очередь, оно проходит через обменник, и именно он решает, в какую именно очередь поместить сообщение.
Queue (Очередь) представляет собой буфер, который хранит сообщения. Очереди очень надёжны, и сообщения можно сделать устойчивыми к перезагрузкам (durable), чтобы не потеряться при падении брокера.
Binding (Привязка) - правило, которое связывает обменник с очередью, указывая, какие сообщения нужно направлять в какую очередь. Может использовать routing key или шаблоны (в случае topic exchange).
Routing Key (Ключ маршрутизации) - это метка, которую производитель добавляет к сообщению. Обменник использует её, чтобы решить, куда направить сообщение.
Брокером в RabbitMQ называется сам сервер, который принимает, хранит и доставляет сообщения. Фактически, всю эту систему целиком можно называть RabbitMQ.
Exchange (Обменник) является точкой входа для сообщений от производителя. Обменник сам решает, куда отправить сообщение дальше, на основе правил привязки (binding), ключа маршрутизации (routing key) и типа обменника.
RabbitMQ поддерживает несколько типов обменников (exchanges), которые определяют правила маршрутизации сообщений:
- Direct - сообщение отправляется в очередь, которая соответствует ключу маршрутизации;
- Fanout - сообщение рассылается во все очереди, связанные с этим обменником;
- Topic - сообщение отправляется в очереди, соответствующие шаблону ключа маршрутизации;
Headers - маршрутизация основана на заголовках сообщения, а не на ключе.
Message Acknowledgment (ACK) - механизм подтверждения: потребитель говорит «я обработал», и сообщение удаляется. Если не подтвердил — оно возвращается в очередь.
Quorum Queues - современный тип очереди, обеспечивающий высокую доступность и отказоустойчивость за счёт репликации и согласованности (как в распределённых системах).
Streams - новый режим работы RabbitMQ (начиная с версии 3.9), позволяющий работать с данными как с логами событий (похоже на Kafka). Подходит для потоковой передачи (streaming), когда нужно читать историю сообщений.
Virtual Host — это изолированное пространство внутри RabbitMQ, которое позволяет разделять ресурсы (очереди, обменники, пользователи) между различными проектами или командами. Каждый Virtual Host имеет свои собственные очереди, обменники и разрешения.
Создать Virtual Host можно через консоль или веб-интерфейс. RabbitMQ предоставляет встроенный веб-интерфейс для мониторинга и управления брокером. Этот интерфейс называется RabbitMQ Management, который представляет собой плагин rabbitmq_management.
RabbitMQ Management по умолчанию доступен по адресу http://localhost:15672 под учётными данными guest/guest (логин/пароль). Интерфейс позволяет просматривать статистику (количество сообщений, скорость обработки, использование памяти), состояние очередей, обменников и соединений, создавать и удалять очереди, обменники.
Имеются и расширения функциональности (плагины). Например:
- rabbitmq_management — веб-интерфейс,
- rabbitmq_shovel — пересылка сообщений между брокерами,
- rabbitmq_federation — объединение нескольких RabbitMQ в сеть.
Как настроить RabbitMQ?
- Установка Erlang на сервер — это зависимость для RabbitMQ (он работает поверх Erlang). Пример:
sudo apt update
sudo apt install erlang
- Установка RabbitMQ. Сначала нужно добавить официальный репозиторий RabbitMQ:
sudo apt-get install curl gnupg
curl -fsSL https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc | sudo gpg --dearmor > /usr/share/keyrings/rabbitmq-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/rabbitmq-archive-keyring.gpg] https://dl.cloudsmith.io/public/rabbitmq/rabbitmq-server/deb/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/rabbitmq.list
sudo apt update
А затем установить RabbitMQ:
sudo apt install rabbitmq-server
- Запуск RabbitMQ. Для этого нужно запустить службу RabbitMQ:
sudo systemctl start rabbitmq-server
Желательно также включить автозапуск RabbitMQ при загрузке системы:
sudo systemctl enable rabbitmq-server
Чтобы убедиться в корректности запуска, можно проверить статус:
sudo systemctl status rabbitmq-server
- Создание виртуального хоста для изоляции проектов:
sudo rabbitmqctl add_vhost my_vhost
- Настройка прав доступа к виртуальному хосту.
Создание пользователя:
sudo rabbitmqctl add_user my_user my_password
Назначение прав на виртуальный хост:
sudo rabbitmqctl set_permissions -p my_vhost my_user ".*" ".*" ".*"
- Включение плагина управления.
Активировать веб-интерфейс:
sudo rabbitmq-plugins enable rabbitmq_management
Веб-интерфейс будет доступен по адресу http://localhost:15672
- Подключение к RabbitMQ.
В разных языках программирования используются соответствующие клиентские библиотеки. Нужно добавить к проекту программы библиотеку, а затем:
- создать соединение с RabbitMQ, указав хост, порт и учётные данные;
- создать канал (логическое соединение внутри физического соединения - все операции выполняются через канал);
- создать обменник с указанием типа;
- создать очередь с уникальным именем;
- связать обменник с очередью, указав ключ маршрутизации.
7.1. C# - библиотека RabbitMQ.Client.
Пример использования:
using RabbitMQ.Client;
using System.Text;
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
// Создание очереди
channel.QueueDeclare(queue: "my_queue", durable: false, exclusive: false, autoDelete: false, arguments: null);
// Отправка сообщения
string message = "Hello, RabbitMQ!";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "", routingKey: "my_queue", basicProperties: null, body: body);
Console.WriteLine("Message sent");
}
7.2. Java - библиотека amqp-client. Пример использования:
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
public class RabbitMQExample {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
// Создание очереди
channel.queueDeclare("my_queue", false, false, false, null);
// Отправка сообщения
String message = "Hello, RabbitMQ!";
channel.basicPublish("", "my_queue", null, message.getBytes());
System.out.println("Message sent");
}
}
}
7.3. Python - библиотека pika. Пример использования:
import pika
# Подключение к RabbitMQ
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
# Создание очереди
channel.queue_declare(queue='my_queue')
# Отправка сообщения
channel.basic_publish(exchange='', routing_key='my_queue', body='Hello, RabbitMQ!')
print("Message sent")
connection.close()
7.4. JavaScript (Node.js) - библиотека amqplib. Пример использования:
const amqp = require('amqplib');
async function sendMessage() {
const connection = await amqp.connect('amqp://localhost');
const channel = await connection.createChannel();
// Создание очереди
const queue = 'my_queue';
await channel.assertQueue(queue, { durable: false });
// Отправка сообщения
const message = 'Hello, RabbitMQ!';
channel.sendToQueue(queue, Buffer.from(message));
console.log("Message sent");
setTimeout(() => {
connection.close();
}, 500);
}
sendMessage();
7.5. PHP - библиотека php-amqplib. Пример использования:
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
// Создание очереди
$channel->queue_declare('my_queue', false, false, false, false);
// Отправка сообщения
$msg = new AMQPMessage('Hello, RabbitMQ!');
$channel->basic_publish($msg, '', 'my_queue');
echo "Message sent\n";
$channel->close();
$connection->close();
- Отправка и получение сообщений. Отправка сообщения (Producer) выполняется через обменник. Получение сообщения (Consumer) выполняется из очереди. Нужно подписаться на очередь и получить сообщение.
- Мониторинг. В веб-интерфейсе можно анализировать список очередей и статистику, а в разделе Exchanges можно увидеть обменники и их привязки.
- Масштабирование. Для масштабирования можно настроить кластер RabbitMQ. Но важно убедиться, что все узлы кластера имеют одинаковую версию RabbitMQ и Erlang.
Kafka
Apache Kafka — это распределённая потоковая платформа (streaming platform), которая предназначена для обработки больших объёмов данных в реальном времени. Kafka часто используется для построения систем, где требуется высокая производительность, масштабируемость и надёжность. Официальный сайт - https://kafka.apache.org/
Kafka работает в кластере, поддерживает обработку данных в реальном времени и может обрабатывать миллионы сообщений в секунду.

Это работает так:
- Определяются продюсеры (отправляют данные) и консьюмеры (получают данные).
- Создаётся кластер Kafka — группа серверов, называемых брокерами.
- Для потока данных создаётся топик — это как лог событий, куда можно только добавлять записи.
- Продюсеры отправляют сообщения в топик (режим PUSH).
- Консьюмеры сами забирают данные из топика (режим PULL), когда готовы их обработать.
- Каждый топик делится на партиции — это позволяет обрабатывать данные параллельно и масштабироваться.
- Партиции распределяются между брокерами кластера для равномерной нагрузки.
- Каждая партиция реплицируется на несколько брокеров — это обеспечивает отказоустойчивость.
- В каждой репликации одна копия — лидер, она обрабатывает все запросы. Остальные — следят за синхронизацией. Если лидер падает, один из них автоматически становится новым лидером.
Теперь давайте разберём чуть подробнее.
Когда имеется много сервисов, БД, монолитов и прочих источников данных, часто возникает ситуация, когда одни и те же данные нужны многим сервисам, но формат хранения разный. Kafka выступает в качестве масштабируемого и отказоустойчивого инструмента, который может пропускать большие объёмы данных (миллионы!),
Как мы обозначили ранее, в Kafka сообщения называются топиками.
Топики, можно сказать, просто собирают данные, добавляя их снова и снова, не изменяясь и используются только для чтения. Продюсеры (отправители) отправляют данные в топики, а консюмеры (потребители) читают топики. К примеру, это сбор активности с различных систем, потоковая обработка большого количества событий, логирование.
Масштабируемость достигуется за счёт архитектуры кластера и системы партиций. Продюсеры группируются, отправляют сообщения в кластер кафки, а потребители «вытягивают» их. Это классическая модель PUSH (толкать, отправлять)/PULL (вытягивать).

Топики разделяются на партиции, которые распределяются между брокерами в кластере. Поэтому кластер Kafka можно считать группой брокеров, используемых для масштабируемости.
Для надёжности, кластеры используют технику репликации - партиции не просто раскидываются между брокерами, а используют репликацию. Это непростой механизм, который похож на копирование - представьте себе четыре папки и 10 файлов. Каждая папка - брокер, а файл - партиция. Для оптимизации нагрузки, вы закидываете файл №1 в папку №1, файл №2 в папку №2, файл №3 в папку №3, а все остальные файлы (4-10) в папку №4. Это простое перемещение, распределение. Но репликация подразумевает, что во всех четырёх папках будут все 10 файлов, как копии. Зачем это используется? Для распределения нагрузки, чтобы брокер №1 работал с сообщением №1, брокер №2 с сообщением №2, и т.д.
Таким образом, для каждой партиции мы получаем экземпляр реплики. Одна из реплик считается «оригиналом», и называется лидером. Все запросы на запись и чтение проходят через лидера - это гарантирует согласованность. А другие реплики, не являющиеся лидерами, не обслуживают запросы клиентов, а только копируют сообщения от лидера, как бы «синхронизируясь». Если реплика считается синхронизированной, то она может быть избрана в качестве лидера раздела. Смена лидера происходит тогда, когда существующий лидер вышел из строя.
Администратор может настроить максимальные размеры сообщений (к примеру, 1 МБ), а также время хранения данных и уровень репликации.
Основные компоненты Kafka:
- Брокер (Broker) — это узел (сервер) в Kafka-кластере, который отвечает за хранение и управление данными. Каждый брокер хранит часть данных (топиков) и обрабатывает запросы от продюсеров и консьюмеров. В кластере может быть несколько брокеров для обеспечения отказоустойчивости и масштабируемости.
- Кластер (Cluster) — это группа брокеров, которые работают вместе для обработки данных. Kafka использует ZooKeeper (или Raft в новых версиях) для координации работы брокеров в кластере.
- Координатор (Coordinator) — это специальный брокер, который отвечает за управление группами консьюмеров. Он отслеживает, какие консьюмеры читают данные из каких партиций, и управляет оффсетами.
- Топик (Topic) — это логический канал, через который передаются сообщения. Каждый топик разделяется на партиции (partitions) для параллельной обработки данных.
- Партиция (Partition) — это упорядоченный лог данных внутри топика. Каждая партиция хранится на одном брокере, но может реплицироваться на другие брокеры для отказоустойчивости. Сообщения в партиции имеют строгий порядок, что позволяет гарантировать последовательность обработки.
- Оффсет (Offset) — это уникальный идентификатор сообщения в партиции. Консьюмеры используют оффсеты для отслеживания своего прогресса при чтении данных. Оффсеты сохраняются либо на стороне консьюмера, либо в Kafka.
- Продюсер (Producer) — это приложение или сервис, которое отправляет сообщения в Kafka. Продюсер выбирает топик и партицию для отправки сообщений.
- Консьюмер (Consumer) — это приложение или сервис, которое читает сообщения из Kafka. Консьюмеры организованы в группы (consumer groups), чтобы распределить нагрузку между несколькими экземплярами.
Kafka использует модель «продюсер-брокер-консьюмер» для обработки данных.
Вот как это работает:
- продюсер отправляет сообщения, пишет их в определённый топик;
- сообщения автоматически распределяются по партициям топика;
- каждый брокер хранит данные в партициях - данные сохраняются в течение заданного времени (например, неделя);
- консьюмер подключается к топику и начинает читать сообщения;
- каждый консьюмер в группе получает данные из одной или нескольких партиций;
- координатор следит за тем, какие консьюмеры читают данные и из каких партиций, если консьюмер выходит из строя, его партиции переназначаются другим консьюмерам.
Как настроить Kafka?
- Установка Java. Kafka работает поверх Java, поэтому сначала нужно установить Java Development Kit (JDK).
- Установка ZooKeeper. ZooKeeper — это координатор, который управляет кластером Kafka. В новых версиях Kafka (например, 3.x) ZooKeeper заменяется на Raft, но для старых версий он всё ещё обязателен. 2.1. Скачайте и распакуйте ZooKeeper; 2.2. Настройте конфигурацию. Создайте файл zoo.cfg в папке conf. 2.3. Запустите ZooKeeper
- Установка Kafka. 3.1. Скачайте и распакуйте Kafka. 3.2. Настройте конфигурацию. Файл конфигурации находится в config/server.properties. Основные параметры:
broker.id=1
listeners=PLAINTEXT://localhost:9092
log.dirs=/tmp/kafka-logs
num.partitions=3
3.3. Запустите Kafka:
bin/kafka-server-start.sh config/server.properties
3.4. Чтобы Kafka запускался автоматически при загрузке системы, добавьте скрипт в автозагрузку или используйте systemd. 4. Создание топика. Топик — это логический канал для передачи сообщений. Создайте топик:
bin/kafka-topics.sh --create --topic my_topic --bootstrap-server localhost:9092 --partitions 3 --replication-factor 1
Проверьте список топиков:
bin/kafka-topics.sh --list --bootstrap-server localhost:9092
- Отправка и получение сообщений. Пример отправки сообщения:
bin/kafka-console-producer.sh --topic my_topic --bootstrap-server localhost:9092
Пример получения сообщения:
bin/kafka-console-consumer.sh --topic my_topic --from-beginning --bootstrap-server localhost:9092
- Подключение Kafka к программам. В разных языках программирования испольхуются соответствующие библиотеки. 6.1. Java - библиотека org.apache.kafka:kafka-clients Пример использования:
import org.apache.kafka.clients.producer.*;
import java.util.Properties;
public class KafkaExample {
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
Producer<String, String> producer = new KafkaProducer<>(props);
producer.send(new ProducerRecord<>("my_topic", "key", "Hello, Kafka!"));
producer.close();
}
}
6.2. Python- библиотека kafka-python Пример использования:
from kafka import KafkaProducer
producer = KafkaProducer(bootstrap_servers='localhost:9092')
producer.send('my_topic', value=b'Hello, Kafka!')
producer.flush()
6.3. JavaScript (Node.js)- библиотека kafkajs Пример использования:
const { Kafka } = require('kafkajs');
const kafka = new Kafka({ brokers: ['localhost:9092'] });
const producer = kafka.producer();
await producer.connect();
await producer.send({
topic: 'my_topic',
messages: [{ value: 'Hello, Kafka!' }],
});
await producer.disconnect();
6.4. PHP - библиотека php-rdkafka Пример использования:
<?php
$rk = new RdKafka\Producer();
$rk->addBrokers("localhost:9092");
$topic = $rk->newTopic("my_topic");
$topic->produce(RD_KAFKA_PARTITION_UA, 0, "Hello, Kafka!");
$rk->poll(0);
?>
- Мониторинг предоставляет инструмент для управления кластерами - Kafka Manager. Пример установки:
docker run -it --rm -p 9000:9000 -e ZK_HOSTS="localhost:2181" sheepkiller/kafka-manager
Для визуализации можно использовать Grafana, а Prometheus для сбора метрик.
Другие особенности
Push-модель (от англ. «push» — «толкать») — это подход, при котором сервер отправляет данные клиенту без явного запроса от клиента. Клиент подписывается на события или уведомления, а сервер автоматически передаёт данные, как только они становятся доступны. Примерами являются вебхуки, WebSockets, и SSE.
Сценарии-вебхуки (Webhooks) — это механизм, который позволяет одной системе уведомлять другую систему о событиях в реальном времени. Вместо того чтобы клиентская система периодически запрашивала обновления (например, через API), серверная система отправляет HTTP-запрос на предопределённый URL клиента, когда происходит какое-либо событие.
Как работают вебхуки:
- клиентская система регистрирует свой URL (конечную точку) на серверной системе.
- когда на сервере происходит событие (например, новая транзакция или изменение данных), он отправляет HTTP-запрос (обычно POST) на этот URL.
- клиентская система получает данные и обрабатывает их.
Вебхуки используются, для уведомлений, к примеру, о завершении платежа, о создании лида в CRM-системе. При таком подходе, данные передаются сразу после события, нет необходимости в постоянных запросах к API (такое явление называется polling). Вебхуки используют стандартный HTTP-протокол.

Pull-модель (от англ. «pull» — «тянуть») — это подход, при котором клиент периодически запрашивает данные с сервера. Сервер не инициирует передачу данных, пока клиент не сделает запрос. Примерами является как раз polling, когда клиент регулярно отправляет запросы на сервер, и REST API.
Push-модель

Pull-модель

Apache Kafka использует Pull-модель (потребители самостоятельно запрашивают данные с сервера, подписываясь на топики и «тянут» данные из топиков), а RabbitMQ использует Push-модель (брокер отправляет сообщения потребителям, «толкает» в потребителей, когда они готовы их обработать).
Реализация интеграции
Веб-сервисы
Веб-сервис — это компонент, который предоставляет функциональность через сеть (обычно HTTP), используя стандартные протоколы, такие как SOAP, REST или XML/JSON. Пример: сервис погоды, который возвращает данные о температуре по HTTP-запросу.
SOAP-веб-сервисы используют протокол SOAP, строгую структуру данных и WSDL для описания контрактов. RESTful API это уже более легковесный стиль, основанный на HTTP-методах (GET, POSTи т.д.), часто возвращают JSON.
WCF (Windows Communication Foundation) — это унифицированная платформа Microsoft для создания подключаемых сервисов, поддерживающая различные протоколы передачи данных (HTTP, TCP, MSMQ и др.) и форматы (SOAP, JSON, XML). WCF был анонсирован как «единое решение» для всех видов коммуникаций между сервисами.
WCF включает в себя: Service Contract - интерфейс, описывающий доступные методы сервиса. OperationContract - метод, доступный клиентам. DataContract / DataMember - атрибуты для сериализации объектов. Binding - описание того, как сервис общается (протокол, кодирование, транспорт). Endpoint - конечная точка, через которую клиент взаимодействует с сервисом. Hosting - способ размещения сервиса (сервис можно хостить в IIS, Windows Service, Console App и т.д.).
Чтобы реализовать сервис, к примеру, можно использовать как раз WCF:
- Определить контракт:
[ServiceContract]
public interface IHelloService
{
[OperationContract]
string SayHello(string name);
}
- Реализовать сервис:
public class HelloService : IHelloService
{
public string SayHello(string name)
{
return $"Привет, {name}!";
}
}
- Хостинг (например, в IIS):
<%@ ServiceHost Language="C#" Service="HelloService" %>
- Настройки в web.config:
<system.serviceModel>
<services>
<service name="HelloService">
<endpoint address="" binding="basicHttpBinding" contract="IHelloService"/>
</service>
</services>
</system.serviceModel>
Теперь сервис доступен по адресу /HelloService.svc.
System.ServiceModel - основное пространство имён для работы с WCF. Как раз там и используются основные атрибуты:
[ServiceContract], обозначает интерфейс как контракт сервиса;
[OperationContract], метод, который будет доступен удалённо;
[DataContract], класс, который может быть сериализован для передачи;
[DataMember], свойство класса, которое участвует в сериализации;
ServiceHost, класс для запуска и управления сервисом;
ChannelFactory<T> для создания клиента WCF-сервиса программно;
BasicHttpBinding, WsHttpBinding, NetTcpBinding - разные типы привязок для разных сценариев.
Другой популярный тип сервисов - Web API. Если WCF использует SOAP, HTTP, TCP, MSMQ, и довольной сложный, то Web API использует в основном HTTP и предпочтителен для REST API и микросервисов. Сейчас вместо WCF используют:
- ASP.NET Web API — для RESTful-сервисов.
- gRPC — для высокопроизводительных RPC-вызовов.
- SignalR — для реального времени (чаты, обновления).
- MassTransit / NServiceBus — для шины сообщений и распределённых систем.
Веб-интерфейс
Веб-формы — это интерфейс, который позволяет пользователям вводить данные через браузер. Эти данные затем отправляются на сервер для обработки. В контексте интеграций веб-формы часто используются для взаимодействия между разными системами. К примеру, пользователь заполняет форму на сайте, и данные передаются в CRM-систему. Это тот самый тег form в HTML с атрибутом отправки submit.
Такой подход очень удобен для пользователей, и можно собирать любые данные, необходимые для интеграции. Форма может напрямую отправлять данные в API другой системы, используя, к примеру, GET или POST запросы.
iFrame (inline frame) — это HTML-элемент, который позволяет встраивать внешний контент (например, веб-страницу) внутрь текущей страницы. iFrame создаёт изолированное окно, которое загружает содержимое независимо от родительской страницы. Это тоже вариант интеграции, к примеру, для встраивания платёжных форм, виджетов или интерактивных карт.
Apache Thrift
Apache Thrift — это фреймворк для разработки масштабируемых кросс-языковых сервисов. Он предоставляет инструменты для определения интерфейсов и генерации кода на различных языках программирования.

Thrift использует собственный диалект языка для описания сервисов и данных - IDL. Для передачи данных используется бинарный формат, что делает его быстрее JSON или XML. Разработчик описывает интерфейс сервиса в IDL-файле. Это описание включает методы и типы данных. Компилятор Thrift преобразует IDL-файл в код на целевых языках программирования (например, Java, Python, C++).
Клиентский код используется для вызова методов удаленного сервиса. Серверный код реализует логику методов, которые будут вызываться клиентом. Оба они генерируются.
Клиент и сервер обмениваются данными через сетевое соединение, используя протокол Thrift (например, JSON, Binary). Клиент отправляет запросы, а сервер обрабатывает их и возвращает ответы.
Про Thrift можно почитать здесь https://thrift.apache.org/
IDL (Interface Definition Language) — это язык, предназначенный для описания интерфейсов, данных и взаимодействий между компонентами программного обеспечения. Он используется для определения структуры данных и методов взаимодействия в распределённых системах, где компоненты могут быть написаны на разных языках программирования. Этот язык позволяет определить:
- Структуры данных (structs) - аналог классов или объектов в языках программирования.
- Перечисления (enums) - наборы констант.
- Сервисы (services) - интерфейсы для вызова удалённых процедур (RPC).
- Исключения (exceptions) - обработка ошибок.
- Типы данных - базовые типы (например, строки, числа) и сложные типы (например, списки, карты).
struct User {
1: required string id;
2: required string name;
3: optional string email;
}
enum Status {
ACTIVE = 1,
INACTIVE = 2,
DELETED = 3
}
service UserService {
User getUser(1: string id) throws (1: Exception ex);
bool updateUser(1: User user);
}
Разберём вышеприведённый пример.
- Struct User - определяет структуру данных с полями id, name и email. Поля помечены как обязательные (required) или необязательные (optional).
- Enum Status - пределяет набор возможных состояний пользователя.
- Service UserService - описывает методы, которые будут доступны клиенту. Например, метод getUser принимает параметр id и может выбросить исключение Exception.
IDL в Thrift работает по следующим этапам:
- Описание интерфейса. Разработчик создаёт файл .thrift, используя синтаксис IDL. В этом файле описываются все структуры данных, сервисы и методы.
- Генерация кода. Используя компилятор, файл .thrift преобразуется в код на целевом языке программирования. К примеру, создаётся Java-код для клиента и сервера.
- Реализация сервера. На основе сгенерированного кода разработчик реализует логику сервера.
- Интеграция клиента. Клиент также использует сгенерированный код для вызова методов сервера.
SOAP
SOAP (Simple Object Access Protocol) — это протокол для обмена структурированными данными в веб-сервисах. Он использует XML для форматирования сообщений и работает поверх различных транспортных протоколов, таких как HTTP, SMTP или TCP.
Про SOAP можно почитать на официальном сайте W3 - https://www.w3.org/TR/soap12-part1/

SOAP имеет строгую спецификацию, независим от платформы и языка, поддерживает сложные сценарии, такие как транзакции, безопасность и маршрутизация. Все данные передаются в виде XML, что делает их человекочитаемыми, но менее эффективными по сравнению с бинарными форматами.
SOAP-сообщение представляет собой XML-документ, который состоит из нескольких частей:
- Envelope (конверт), корневой элемент SOAP-сообщения, который определяет начало и конец сообщения.
- Header (заголовок), необязательный элемент, который содержит метаданные, такие как аутентификация, маршрутизация или транзакции.
- Body (тело), обязательный элемент, содержит основные данные запроса или ответа.
- Fault (ошибка), необязательный элемент, используется для передачи информации об ошибках.

Пример:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<auth:Authentication xmlns:auth="http://example.com/auth">
<auth:Token>12345</auth:Token>
</auth:Authentication>
</soap:Header>
<soap:Body>
<getUserRequest xmlns="http://example.com/user">
<userId>1</userId>
</getUserRequest>
</soap:Body>
</soap:Envelope>
Как работает SOAP?
- Клиент отправляет SOAP-запрос на сервер через HTTP POST.
- Сервер обрабатывает запрос и формирует SOAP-ответ.
- Ответ отправляется обратно клиенту.
WSDL (Web Services Description Language) — это язык, используемый для описания веб-сервисов, доступных через SOAP. WSDL предоставляет формальное описание того, какие операции поддерживает сервис, какие данные используются в запросах и ответах, где находится сервис (URL) и какой протокол используется для взаимодействия.

WSDL-документ состоит из нескольких ключевых элементов:
- Types определяет типы данных, используемые в сервисе (например, строки, числа, объекты). Часто использует XML Schema (XSD).
- Message описывает входные и выходные данные для операций.
- PortType определяет набор операций, которые поддерживает сервис.
- Binding описывает протокол (например, SOAP) и формат данных для каждой операции.
- Service указывает URL, где находится сервис.

Как работает взаимодействие SOAP+WSDL?
- Клиент получает WSDL, загружая документ с сервера, чтобы узнать, какие операции доступны и как их вызывать.
- На основе WSDL генерируется код для клиента.
- Клиент вызывает метод, например, getUser, передавая параметры в виде XML.
- Сервер получает SOAP-запрос, выполняет операцию и формирует SOAP-ответ.
- Клиент получает SOAP-ответ и обрабатывает его.
Прочие фреймворки
MessagePack — это бинарный формат сериализации, который является альтернативой JSON. Он разработан для компактного и быстрого обмена данными между системами.
Данные кодируются в бинарном виде. Допустим, у нас есть JSON-объект:
{
"name": "Alice",
"age": 30,
"is_active": true
}
Он будет закодирован в бинарном виде:
83 A4 6E 61 6D 65 A5 41 6C 69 63 65 A3 61 67 65 1E A9 69 73 5F 61 63 74 69 76 65 C3
Это занимает меньше места, чем JSON, и быстрее для парсинга и передачи данных. Как можно заметить, уже и не человекочитаемо.
OpenAPI (Swagger) — это стандарт для описания RESTful API. Он предоставляет формальный способ документирования API, что упрощает взаимодействие между разработчиками и автоматизацию процессов.
OpenAPI предоставляет описание эндпоинтов (указываются URL, методы GET, POST, PUT, DELETE и параметры запроса), описание схемы данных (входных и выходных данных), что позволяет разработчикам понять, как использовать API.
А Swagger UI позволяет тестировать API прямо из браузера.
RESTful подразумевает, что приложение использует архитектурный стиль REST.
Примеры RESTful API:
GET /users- получить список пользователей.POST /users- создать нового пользователя.PUT /users/{id}- обновить пользователя с указанным ID.DELETE /users/{id}- удалить пользователя с указанным ID.
RSocket — это протокол для асинхронного обмена данными, который используется для реактивных систем. Использует бинарный формат (например, Protobuf или JSON) и применяется в чатах, биржах. Поддерживает четыре основных типа взаимодействий:
- Request-Response (запрос-ответ) - клиент отправляет запрос и получает один ответ.
- Fire-and-Forget (выстрелил и забыл) - клиент отправляет запрос без ожидания ответа.
- Request-Stream (запрос-поток) - клиент отправляет запрос и получает поток данных.
- Channel (канал) - двунаправленный обмен данными.
Есть ещё одна платформа, достойная внимания. Это не фреймворк.
IBM MQ (Message Queue) — это корпоративная платформа для асинхронного обмена сообщениями между приложениями, сервисами и системами. Сообщения хранятся в очередях до тех пор, пока не будут обработаны. Использует различные протоколы - JMS, AMQP, MQTT, и даже собственный протокол IBM MQ.
IBM MQ использует модель «производитель-потребитель» через промежуточное хранилище — очередь (queue). Производитель отправляет сообщение в очередь и продолжает работу, не дожидаясь ответа от потребителя.
Message Producer отправляет сообщения в очередь. Он может быть любым приложением или системой. Queue Manager управляет очередями и маршрутизацией сообщений.
Message Consumer получает сообщения из очереди и обрабатывает их согласно логике приложения. Очереди бывают:
- локальные очереди, которые хранят сообщения на одном сервере.
- удалённые очереди, которые пересылают сообщения между разными серверами.
IBM MQ широко используется в крупных организациях, таких как банки, страховые компании и телекоммуникационные компании. Требует лицензирования.
Service Mesh — это инфраструктура для управления взаимодействием между микросервисами. Она предоставляет такие функции, как маршрутизация, балансировка нагрузки, мониторинг и безопасность.
Основные компоненты:
- Sidecar-прокси : прокси-серверы, внедренные в каждый под (например, Envoy).
- Контроллер : управляет конфигурацией и политиками (например, Istio, Linkerd).
Sidecar-прокси — это дополнительный контейнер, который размещается в том же поде, что и основное приложение в Kubernetes. Он используется для выполнения вспомогательных задач, таких как маршрутизация трафика, балансировка нагрузки, мониторинг или шифрование. В Service Mesh (например, Istio) sidecar-прокси (обычно Envoy) автоматически внедряется в каждый под для управления взаимодействием между микросервисами. Jaeger — это система распределенной трассировки, созданная для анализа взаимодействия между микросервисами.
Zipkin — это еще одна система распределенной трассировки, аналогичная Jaeger. Она используется для анализа производительности и диагностики проблем в микросервисах.
Envoy — это высокопроизводительный прокси-сервер и коммуникационная шина для распределенных систем. Он часто используется как sidecar-прокси в архитектурах микросервисов.
Linkerd — это легковесный Service Mesh, разработанный для Kubernetes. Он фокусируется на простоте использования и производительности и позволяет автоматически добавлять прокси в поды, при этом обеспечивая шифрование трафика.
Istio — это Service Mesh, который предоставляет инструменты для управления трафиком, безопасности и наблюдаемости в микросервисной архитектуре.